;;; ycp-complete.el -- My config for minibuffer and completions -*- lexical-binding: t -*- ;; Copyright (C) 2023 Free Software Foundation. ;; Author: Yuchen Pei ;; Protesilaos Stavrou ;; Maintainer: Yuchen Pei ;; Package-Requires: ((emacs "28.2")) ;; This file is part of dotfiles. ;; dotfiles is free software: you can redistribute it and/or modify it under ;; the terms of the GNU Affero General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; dotfiles is distributed in the hope that it will be useful, but WITHOUT ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General ;; Public License for more details. ;; You should have received a copy of the GNU Affero General Public ;; License along with dotfiles. If not, see . ;;; Commentary: ;; My config for minibuffer and completions. ;;; Code: ;; completion, minibuffer, corfu, tempel ;; part adapted from prot-dotfiles (my-package minibuffer (setq completion-styles '(basic partial-completion emacs22 orderless)) (setq completion-category-overrides ;; NOTE 2021-10-25: I am adding `basic' because it works better as a ;; default for some contexts. Read: ;; . ;; ;; `partial-completion' is a killer app for files, because it ;; can expand ~/.l/s/fo to ~/.local/share/fonts. ;; ;; If `basic' cannot match my current input, Emacs tries the ;; next completion style in the given order. In other words, ;; `orderless' kicks in as soon as I input a space or one of its ;; style dispatcher characters. '((file (styles . (basic partial-completion orderless))) (project-file (styles . (basic substring partial-completion orderless))) (imenu (styles . (emacs22 substring orderless))) (kill-ring (styles . (emacs22 substring orderless))) (consult-location (styles . (emacs22 substring orderless))) (eglot (styles . (emacs22 substring orderless))))) (setq completion-ignore-case t) (setq read-buffer-completion-ignore-case t) (setq read-file-name-completion-ignore-case t) ;; disable space to run minibuffer-complete-word (my-keybind minibuffer-mode-map "SPC" nil "?" nil) (my-keybind minibuffer-local-completion-map "SPC" nil "?" nil) (setq enable-recursive-minibuffers t) (minibuffer-depth-indicate-mode 1) (setq resize-mini-windows t) (setq read-answer-short t) (setq echo-keystrokes 0.25) ;; Do not allow the cursor to move inside the minibuffer prompt. I ;; got this from the documentation of Daniel Mendler's Vertico ;; package: . (setq minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt)) (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode) (minibuffer-electric-default-mode 1)) ;;;; `savehist' (minibuffer and related histories) (my-package savehist (setq savehist-file (locate-user-emacs-file "savehist")) (setq history-length 500) (setq history-delete-duplicates t) (setq savehist-save-minibuffer-history t) (setq savehist-additional-variables '(register-alist kill-ring)) (savehist-mode 1)) ;;;; `dabbrev' (dynamic word completion (dynamic abbreviations)) (my-package dabbrev (setq dabbrev-abbrev-char-regexp "\\sw\\|\\s_") (setq dabbrev-abbrev-skip-leading-regexp "[$*/=~']") (setq dabbrev-backward-only nil) (setq dabbrev-case-distinction 'case-replace) (setq dabbrev-case-fold-search nil) (setq dabbrev-case-replace 'case-replace) (setq dabbrev-check-other-buffers t) (setq dabbrev-eliminate-newlines t) (setq dabbrev-upcase-means-case-search t)) ;;; icomplete (my-package icomplete (icomplete-vertical-mode t) (setq icomplete-show-matches-on-no-input t) (setq icomplete-prospects-height 4) (setq icomplete-scroll t) (setq icomplete-matches-format "[%s/%s] ") (require 'my-complete) (my-keybind icomplete-minibuffer-map "" #'icomplete-force-complete "M-" #'minibuffer-complete "C-M-i" #'minibuffer-complete "C-s" #'icomplete-forward-completions "C-r" #'icomplete-backward-completions "C-v" #'my-icomplete-vertical-forward-page "M-v" #'my-icomplete-vertical-backward-page)) (my-package recentf (setq recentf-max-saved-items 1000) (setq recentf-exclude '("~\\'" "\\`out\\'" "\\.log\\'" "^/[^/]*:" "\\.el\\.gz\\'" "~$" "/mnt/" "^/tmp/")) (recentf-mode 1) ;; disable recentf-save-list on quit on non-emacs-client so that it does not ;; overwrite the recentf file (require 'my-utils) (unless (my-server-p) (setq kill-emacs-hook (delete 'recentf-save-list kill-emacs-hook))) (require 'my-complete) (my-server-timer recentf-timer nil 300 'my-recentf-save-list-silently) ) ;;; corfu (my-package corfu (:install t) (:delay 5) (global-corfu-mode 1) (corfu-popupinfo-mode 1) (setq corfu-auto t corfu-cycle t corfu-separator ?\s) (define-key corfu-map [remap next-line] nil) (define-key corfu-map [remap previous-line] nil) (define-key corfu-map [remap beginning-of-buffer] nil) (define-key corfu-map [remap end-of-buffer] nil) (my-keybind corfu-map "C-j" 'corfu-insert "" 'nil "C-s" #'corfu-next "C-r" #'corfu-previous) (require 'my-corfu) (add-hook 'minibuffer-setup-hook #'my-corfu-enable-always-in-minibuffer 1) ) ;;; cape (my-package cape (:install t) (:delay 15) (setq cape-dabbrev-min-length 3) (setq cape-symbol-wrapper '((org-mode ?~ ?~) (markdown-mode ?` ?`) (log-edit-mode ?' ?') (message-mode ?' ?'))) (dolist (backend '( cape-symbol cape-keyword cape-file cape-history cape-dabbrev)) (add-to-list 'completion-at-point-functions backend))) ;;; consult (my-package consult (:install t) (:delay 10) (setq consult-line-numbers-widen t) ;; (setq completion-in-region-function #'consult-completion-in-region) (setq consult-async-min-input 3) (setq consult-async-input-debounce 0.5) (setq consult-async-input-throttle 0.8) (setq consult-narrow-key ">") (setq register-preview-delay 0.8 register-preview-function #'consult-register-format) (setq consult-find-args "find . -not ( -path */.git* -prune )") (setq consult-preview-key 'any) (add-to-list 'consult-mode-histories '(vc-git-log-edit-mode . log-edit-comment-ring)) (add-hook 'completion-list-mode-hook #'consult-preview-at-point-mode) (require 'consult-imenu) ; the `imenu' extension is in its own file (require 'my-consult) (my-keybind global-map "C-x b" #'consult-buffer "C-z" #'consult-buffer "C-x l" #'consult-locate "M-g M-g" #'consult-goto-line "M-K" #'consult-keep-lines ; M-S-k is similar to M-S-5 (M-%) "M-F" #'consult-focus-lines ; same principle "M-s M-b" #'consult-buffer "M-s M-f" #'consult-find "M-s M-G" #'consult-grep "M-s M-g" #'my-consult-grep-default "M-s M-h" #'consult-history "M-s M-i" #'consult-imenu "M-s M-l" #'consult-line "M-s M-m" #'consult-mark "M-y" #'consult-yank-pop "M-s M-s" #'consult-outline) (my-keybind consult-narrow-map "?" #'consult-narrow-help) (my-keybind minibuffer-local-map "C-s" #'consult-history) ) ;;; marginalia (my-package marginalia (:install t) (:delay 10) (setq marginalia-max-relative-age 0) (marginalia-mode 1)) (setq tempel-path (locate-user-emacs-file "*tempel-templates")) (my-package tempel (:install t) (:delay 15) (require 'my-tempel) (my-keybind global-map "M-=" #'tempel-complete ; Alternative: `tempel-expand' "M-*" #'tempel-insert) (my-keybind tempel-map "RET" #'tempel-done "C-p" #'tempel-previous "C-n" #'tempel-next "" #'tempel-next "" #'tempel-previous "C-S-" #'tempel-previous) (require 'my-tempel) (dolist (hook '(prog-mode-hook text-mode-hook)) (add-hook hook 'my-tempel-setup-capf)) ) ;; consult-recoll (my-package consult-recoll (:delay 30) (:install t) ) (my-package hmm (:delay 60) (my-setq-from-local hmm-web-search-engines) (require 'my-net) (setq hmm-web-browsers '((:name eww :command eww) (:name luwak :command luwak-open) (:name firefox :command browse-url-firefox) (:name firefox-private :command my-browse-url-firefox-private) (:name tor-browser :command my-browse-url-tor-browser) (:name download-and-open :command my-fetch-url))) (setq hmm-handlers '(:query ((:command servall-ytdl-search) (:command servall-wikipedia-open) (:command servall-wikipedia-search) (:command hcel-global-ids) (:command osm-search) (:command my-org-recoll-mdn) (:command consult-recoll) (:command locate) (:command project-or-external-find-regexp) (:command dictionary-search) (:command my-libgen-search) (:command my-libgen-search-isbn) (:command my-openlibrary-search) ;; TODO: sx, grep-somewhere, grep-here, gnus news, gnus email ;; rt-liber (some sort of smart search) ) ;; URL handlers handle all schemes, including file: ;; We want to add all file-handlers here with regex that filters ;; file: in scheme :url ((:schemes ("http" "https") :regex "^en.wikipedia.org/wiki/.*$" :command servall-wikipedia-open) (:schemes ("http" "https") :regex "^\\(?:.*\\.\\)?\\(?:stackexchange\\|stackoverflow\\|mathoverflow\\|askubuntu\\)\\.com/.*$" :command sx-open-link) (:schemes ("http" "https") :regex "^\\(?:.*\\.\\)?news.ycombinator.com/.*$" :command hnreader-comment) (:schemes ("http" "https") :command my-org-grok) (:schemes ("mailto") :command browse-url-mail) (:schemes ("mailto") :command my-gnus-fastmail-mail-url) (:schemes ("http" "https") :command my-ytdl-audio) (:schemes ("http" "https") :command my-ytdl-video) (:schemes ("http" "https") :command my-describe-package-from-url :regex "^\\(?:elpa.gnu.org/packages\\|elpa.gnu.org/devel\\|elpa.nongnu.org/nongnu\\)\\(?:/.*\\).html") (:command emms-play-url :schemes ("ftp" "http" "https" "mms" "rtmp" "rtsp" "sftp" "smb" "srt") ) ;;FIXME: buggy ;; TODO: magit-clone-shallow, osm ) :file ;; by mimetypes / extensions etc, most can be handled by find-file? ;; shell can be used for dir ((:command find-file) (:command dired :mimetypes ("inode/directory")) (:command my-shell-with-directory :mimetypes ("inode/directory")) (:command magit-status :mimetypes ("inode/directory")) (:command byte-compile-file :mimetypes ("text/x-lisp")) (:command hmm-file-mime-type)))) (setq hmm-external-handlers '((:name mpv :external-command "mpv %U" :display-name "mpv player" :description "Play url with mpv" :schemes ("ftp" "http" "https" "mms" "rtmp" "rtsp" "sftp" "smb" "srt") :handling :url) (:name wget :external-command "wget %U" :display-name "GNU Wget" :description "The non-interactive network downloader" :schemes ("ftp" "http" "https") :handling :url) (:name qutebrowser :external-command "qutebrowser %U" :display-name "qutebrowser" :description "A keyboard-driven, vim-like browser based on PyQt5" :schemes ("http" "https") :handling :url) (:name torsocks-mpv :external-command "torsocks mpv %U" :display-name "mpv player torsocks" :description "Play url with mpv over torsocks" :schemes ("ftp" "http" "https" "mms" "rtmp" "rtsp" "sftp" "smb" "srt") :handling :url) (:name clean-elc-compile :external-command "clean-elc-compile %f" :description "Clean compile a directory of elisp files" :display-buffer t :mimetypes ("inode/directory") :handling :file) (:name mogrify-strip :external-command "mogrify -strip %F" :description "Strip images of all profiles and comments" :display-buffer t :handling :file) (:name pacfind :external-command "pacfind %f" :description "Find the pacman package containing a command" :display-buffer t :handling :query))) (setq hmm-matchers '(((thing-at-point-url-at-point) . hmm-url) ((thing-at-point-file-at-point) . hmm-file) ((and (derived-mode-p 'dired-mode) (dired-get-filename nil t)) . hmm-file) ((and (derived-mode-p 'dired-mode) (expand-file-name default-directory)) . hmm-file) ((and (derived-mode-p 'org-mode) (my-org-link-at-point)) . hmm-url) ((get-text-property (point) 'shr-url) . hmm-url) ((and (derived-mode-p 'luwak-mode) (get-text-property (point) 'url)) . hmm-url) ((and (derived-mode-p 'luwak-mode) (plist-get luwak-data :url)) . hmm-url) ((thing-at-point 'symbol) . hmm-query) ((buffer-file-name) . hmm-file) ((expand-file-name default-directory) . hmm-file))) (hmm-update)) (provide 'ycp-complete)