563 lines
19 KiB
EmacsLisp
563 lines
19 KiB
EmacsLisp
;; -*- lexical-binding: t; -*-
|
|
(require 'package)
|
|
|
|
(setq package-vc-register-as-project nil) ; Emacs 30
|
|
|
|
(add-hook 'package-menu-mode-hook #'hl-line-mode)
|
|
|
|
;; List of packages for auto install scratch
|
|
(setq package-list '(use-package))
|
|
|
|
|
|
;; Also read: <https://protesilaos.com/codelog/2022-05-13-emacs-elpa-devel/>
|
|
(setq package-archives
|
|
'(("gnu-elpa" . "https://elpa.gnu.org/packages/")
|
|
("gnu-elpa-devel" . "https://elpa.gnu.org/devel/")
|
|
("nongnu" . "https://elpa.nongnu.org/nongnu/")
|
|
("melpa" . "https://melpa.org/packages/")))
|
|
|
|
;; Highest number gets priority (what is not mentioned has priority 0)
|
|
(setq package-archive-priorities
|
|
'(("gnu-elpa" . 3)
|
|
("melpa" . 2)
|
|
("nongnu" . 1)))
|
|
|
|
;; NOTE 2023-08-21: I build Emacs from source, so I always get the
|
|
;; latest version of built-in packages. However, this is a good
|
|
;; solution to set to non-nil if I ever switch to a stable release.
|
|
(setq package-install-upgrade-built-in nil)
|
|
|
|
; activate all the packages (in particular autoloads)
|
|
(package-initialize)
|
|
|
|
; fetch the list of packages available
|
|
(unless package-archive-contents
|
|
(package-refresh-contents))
|
|
|
|
|
|
;; Whitespace-mode settings.
|
|
(use-package emacs
|
|
:init
|
|
(custom-set-variables '(whitespace-display-mappings '((space-mark 32 [183] [46])
|
|
(space-mark 160 [164] [95])
|
|
(newline-mark 10 [172 10])
|
|
(tab-mark 9 [187 9] [92 9]))))
|
|
(custom-set-faces
|
|
'(whitespace-space ((t (:bold t :foreground "#282828"))))
|
|
'(whitespace-newline ((t (:bold t :foreground "#282828"))))
|
|
)
|
|
(add-hook 'prog-mode-hook (lambda () (setq display-line-numbers 'relative)))
|
|
(add-hook 'prog-mode-hook 'whitespace-mode)
|
|
)
|
|
|
|
;; Frame settings.
|
|
(use-package emacs
|
|
:init
|
|
(setq initial-frame-alist '(
|
|
(fullscreen . maximized)
|
|
(font . "JetBrains Mono 22")
|
|
;; (font . "Iosevka Fixed 24")
|
|
(undecorated . t)
|
|
(vertical-scroll-bars . nil)
|
|
(inhibit-double-buffering . t)
|
|
;; (ns-transparent-titlebar . nil)
|
|
(background-color . "#181818") ;;"black")
|
|
))
|
|
)
|
|
|
|
;; Basic settings.
|
|
(use-package emacs
|
|
:init
|
|
(delete-selection-mode 1)
|
|
(blink-cursor-mode 0)
|
|
(save-place-mode t)
|
|
(savehist-mode t)
|
|
(setq use-short-answers t
|
|
ring-bell-function 'ignore
|
|
scroll-conservatively 101
|
|
help-window-select t
|
|
create-lockfiles nil
|
|
auto-save-default nil
|
|
make-backup-files nil
|
|
custom-safe-themes t
|
|
initial-buffer-choice nil ;; If not nil always show scratch buffer, even open other file.
|
|
backup-directory-alist '((".*" . "/tmp"))
|
|
custom-file (make-temp-file "emacs-custom-")
|
|
whitespace-style (quote (face spaces tabs space-mark tab-mark newline newline-mark))
|
|
Man-sed-command "gsed")
|
|
:config
|
|
(setq-default truncate-lines nil
|
|
display-line-numbers-width 3
|
|
indent-tabs-mode nil
|
|
tab-width 4
|
|
c-basic-offset 4
|
|
c-basic-indent 4)
|
|
(xterm-mouse-mode t)
|
|
(show-paren-mode t))
|
|
|
|
;; Mode line format. -----
|
|
(defun my-evil-mode-indicator ()
|
|
(interactive)
|
|
(cond ((eq evil-state 'visual) "<V>")
|
|
((eq evil-state 'insert) "<I>")
|
|
((eq evil-state 'normal) "<N>")
|
|
((eq evil-state 'emacs) "<E>")
|
|
(t " * ")))
|
|
(setq-default mode-line-format '("%e " mode-line-modified " "
|
|
(:eval (propertize (buffer-name)) 'face 'font-lock-constant-face)
|
|
"%6l:%c (%o) "
|
|
(:eval
|
|
(if (and (mode-line-window-selected-p) (bound-and-true-p evil-mode))
|
|
(my-evil-mode-indicator))
|
|
" ")
|
|
(:eval (unless (not vc-mode) (concat " | git:" (substring-no-properties vc-mode 5))))
|
|
mode-line-format-right-align
|
|
(:eval (concat " " (symbol-name major-mode)))
|
|
" " mode-line-misc-info))
|
|
|
|
(use-package emacs
|
|
:init
|
|
;; Add prompt indicator to `completing-read-multiple'.
|
|
;; We display [CRM<separator>], e.g., [CRM,] if the separator is a comma.
|
|
(defun crm-indicator (args)
|
|
(cons (format "[CRM%s] %s"
|
|
(replace-regexp-in-string
|
|
"\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
|
|
crm-separator)
|
|
(car args))
|
|
(cdr args)))
|
|
(advice-add #'completing-read-multiple :filter-args #'crm-indicator)
|
|
;; Do not allow the cursor in the minibuffer prompt
|
|
(setq minibuffer-prompt-properties
|
|
'(read-only t cursor-intangible t face minibuffer-prompt))
|
|
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
|
|
;; (add hook 'rfn-eshadow-update-overlay-hook #'vertico-directory-tidy)
|
|
;; Enable recursive minibuffers
|
|
(setq enable-recursive-minibuffers t))
|
|
|
|
|
|
(use-package modus-themes
|
|
:ensure t
|
|
:defer t
|
|
:config
|
|
(custom-set-faces
|
|
'(dired-header ((t (:foreground "#95a99f" :slant italic)))))
|
|
(custom-set-faces
|
|
'(dired-directory ((t (:foreground "#96a6c8" :slant italic)))))
|
|
(setq modus-themes-italic-constructs nil
|
|
modus-themes-bold-constructs nil
|
|
modus-themes-mixed-fonts nil
|
|
modus-themes-variable-pitch-ui nil
|
|
modus-themes-custom-auto-reload t
|
|
modus-themes-disable-other-themes t
|
|
modus-themes-prompts '(italic bold)
|
|
modus-themes-completions
|
|
'((matches . (extrabold))
|
|
(selection . (semibold italic text-also)))
|
|
modus-themes-org-blocks 'tined-background
|
|
)
|
|
(setq modus-vivendi-palette-overrides
|
|
;; Setting for theme like gruber-darker
|
|
`(
|
|
(fg-main "#e4e4ef")
|
|
;; Background
|
|
(bg-main "#181818")
|
|
;; Comment and string
|
|
(comment "#cc8c3c") ;; yellow-faint)
|
|
(string "#73c936")
|
|
;; Code colors
|
|
(builtin "#95a99f")
|
|
(constant "#95a99f")
|
|
(fnname "#96a6c8")
|
|
(keyword "#ffdd33")
|
|
(preprocessor "#95a99f")
|
|
(type "#95a99f")
|
|
(cursor "#ffdd33")
|
|
(variable "#f4f4ff")
|
|
(bg-region "#484848")
|
|
(fg-region unspecified)
|
|
(fg-completion-match-0 "#ffdd33")
|
|
(fg-prompt "#96a6c8")
|
|
(bg-mode-line-active "#282828")
|
|
(fg-mode-line-active "#ffffff")
|
|
(fg-line-number-active "#ffdd33")
|
|
(bg-line-number-active "#181818")
|
|
(bg-line-number-inactive "#181818")
|
|
;; SRC-block
|
|
(bg-prose-block-delimiter bg-cyan-nuanced)
|
|
;; Region bg and fg
|
|
(bg-region bg-hover) ; try to replace `bg-ochre' with `bg-lavender', `bg-sage'
|
|
(fg-region unspecified)
|
|
)))
|
|
(load-theme 'modus-vivendi t)
|
|
|
|
;; Denote package. ----
|
|
(use-package denote
|
|
:ensure t
|
|
:init
|
|
:custom
|
|
(denote-directory "~/Nextcloud/DenoteNotes/")
|
|
:hook
|
|
(dired-mode . denote-dired-mode)
|
|
:custom-face
|
|
(denote-faces-link ((t (:slant italic)))))
|
|
(global-set-key (kbd "C-c n n") 'denote-open-or-create)
|
|
|
|
(use-package consult-denote
|
|
:ensure t
|
|
:config
|
|
(define-key global-map (kbd "C-c n f") #'consult-denote-find)
|
|
(define-key global-map (kbd "C-c n g") #'consult-denote-grep))
|
|
|
|
(use-package vertico
|
|
:ensure t
|
|
:init
|
|
(setq vertico-scroll-margin 0)
|
|
(setq vertico-count 5)
|
|
(setq vertico-resize nil)
|
|
(setq vertico-cycle t)
|
|
(vertico-mode))
|
|
|
|
(use-package emacs
|
|
:custom
|
|
;; Support opening new minibuffers from inside existing minibuffers.
|
|
(enable-recursive-minibuffers t)
|
|
;; Hide commands in M-x which do not work in the current mode. Vertico
|
|
;; commands are hidden in normal buffers. This setting is useful beyond
|
|
;; Vertico.
|
|
(read-extended-command-predicate #'command-completion-default-include-p)
|
|
;; Do not allow the cursor in the minibuffer prompt
|
|
(minibuffer-prompt-properties
|
|
'(read-only t cursor-intangible t face minibuffer-prompt)))
|
|
|
|
;; Dired module. -----
|
|
(when (string= system-type "darwin")
|
|
(setq dired-use-ls-dired nil))
|
|
(use-package dired
|
|
:init
|
|
(setq delete-by-moving-to-trash t)
|
|
(setq dired-listing-switches "-lah")
|
|
(setq dired-dwim-target t)
|
|
(setq dired-auto-revert-buffer #'dired-directory-changed-p)
|
|
)
|
|
|
|
;; ISearch module. -----
|
|
(use-package isearch
|
|
:ensure nil
|
|
:demand t
|
|
:config
|
|
(setq search-whitespace-regexp ".*?" ; one `setq' here to make it obvious they are a bundle
|
|
isearch-lax-whitespace t
|
|
isearch-regexp-lax-whitespace nil))
|
|
(use-package isearch
|
|
:ensure nil
|
|
:demand t
|
|
:config
|
|
(setq search-highlight t)
|
|
(setq isearch-lazy-highlight t)
|
|
(setq lazy-highlight-initial-delay 0.5)
|
|
(setq lazy-highlight-no-delay-length 4))
|
|
(use-package isearch
|
|
:ensure nil
|
|
:demand t
|
|
:config
|
|
(setq isearch-lazy-count t)
|
|
(setq lazy-count-prefix-format "(%s/%s) ")
|
|
(setq lazy-count-suffix-format nil))
|
|
(use-package isearch
|
|
:ensure nil
|
|
:demand t
|
|
:config
|
|
(setq isearch-wrap-pause t) ; `no-ding' makes keyboard macros never quit
|
|
(setq isearch-repeat-on-direction-change t))
|
|
(use-package isearch
|
|
:ensure nil
|
|
:demand t
|
|
:config
|
|
(setq list-matching-lines-jump-to-current-line nil) ; do not jump to current line in `*occur*' buffers
|
|
;; (add-hook 'occur-mode-hook #'prot-common-truncate-lines-silently) ; from `prot-common.el'
|
|
(add-hook 'occur-mode-hook #'hl-line-mode))
|
|
(use-package isearch
|
|
:ensure nil
|
|
:defer t
|
|
:config
|
|
(defun my-occur-from-isearch ()
|
|
(interactive)
|
|
(let ((query (if isearch-regexp
|
|
isearch-string
|
|
(regexp-quote isearch-string))))
|
|
(isearch-update-ring isearch-string isearch-regexp)
|
|
(let (search-nonincremental-instead)
|
|
(ignore-errors (isearch-done t t)))
|
|
(occur query)))
|
|
:bind
|
|
(:map isearch-mode-map
|
|
("C-o" . my-occur-from-isearch)))
|
|
(use-package isearch
|
|
:ensure nil
|
|
:defer t
|
|
:config
|
|
(defun my-project-search-from-isearch ()
|
|
(interactive)
|
|
(let ((query (if isearch-regexp
|
|
isearch-string
|
|
(regexp-quote isearch-string))))
|
|
(isearch-update-ring isearch-string isearch-regexp)
|
|
(let (search-nonincremental-instead)
|
|
(ignore-errors (isearch-done t t)))
|
|
(project-find-regexp query)))
|
|
:bind
|
|
(:map isearch-mode-map
|
|
("C-f" . my-project-search-from-isearch)))
|
|
|
|
|
|
;; Selection window (rg, grep, help etc). -----
|
|
(defun my-select-window (window &rest _)
|
|
"Select WINDOW for display-buffer-alist"
|
|
(select-window window))
|
|
|
|
(setq display-buffer-alist
|
|
'(((or . ((derived-mode . occur-mode)
|
|
(derived-mode . rg-mode)
|
|
(derived-mode . grep-mode)
|
|
(derived-mode . Buffer-menu-mode)
|
|
(derived-mode . log-view-mode)
|
|
(derived-mode . help-mode) ; See the hooks for `visual-line-mode'
|
|
(derived-mode . flymake-diagnostics-buffer-mode)
|
|
"\\*\\(|Buffer List\\|Occur\\|vc-change-log\\|compilation\\|eldoc.*\\).*"
|
|
))
|
|
(display-buffer-reuse-mode-window display-buffer-pop-up-window)
|
|
(body-function . my-select-window)
|
|
(dedicated . t)
|
|
(preserve-size . (t . t)))))
|
|
|
|
;; Marginalia. -----
|
|
(use-package marginalia
|
|
:ensure t
|
|
;; Either bind `marginalia-cycle' globally or only in the minibuffer
|
|
:bind (("M-A" . marginalia-cycle)
|
|
:map minibuffer-local-map
|
|
("M-A" . marginalia-cycle))
|
|
|
|
;; The :init configuration is always executed (Not lazy!)
|
|
:init
|
|
|
|
;; Must be in the :init section of use-package such that the mode gets
|
|
;; enabled right away. Note that this forces loading the package.
|
|
(marginalia-mode))
|
|
|
|
;; Orderless. -----
|
|
(use-package orderless
|
|
:ensure t
|
|
:demand t
|
|
:after minibuffer
|
|
:config
|
|
(setq completion-styles '(orderless basic)
|
|
completion-category-defaults nil
|
|
;; orderless-matching-styles '(orderless-prefixes orderless-regexp)
|
|
completion-category-overrides '((file (styles . (partial-completion))))
|
|
))
|
|
|
|
;; Corfu
|
|
(use-package corfu
|
|
:ensure t
|
|
:defer 3
|
|
:custom
|
|
(corfu-cycle t) ;; Enable cycling for `corfu-next/previous'
|
|
(corfu-auto t) ;; Enable auto completion
|
|
;; (corfu-separator ?\s) ;; Orderless field separator
|
|
;; (corfu-quit-at-boundary nil) ;; Never quit at completion boundary
|
|
;; (corfu-quit-no-match nil) ;; Never quit, even if there is no match
|
|
;; (corfu-preview-current nil) ;; Disable current candidate preview
|
|
;; (corfu-preselect 'prompt) ;; Preselect the prompt
|
|
;; (corfu-on-exact-match nil) ;; Configure handling of exact matches
|
|
;; (corfu-scroll-margin 5) ;; Use scroll margin
|
|
(corfu-popupinfo-mode t)
|
|
|
|
:bind (:map corfu-map
|
|
("C-y" . corfu-complete)
|
|
("C-e" . corfu-reset)
|
|
("<TAB>" . nil)
|
|
)
|
|
:init
|
|
(global-corfu-mode))
|
|
|
|
(use-package corfu-terminal
|
|
:ensure t
|
|
:defer 3
|
|
:init
|
|
(unless (display-graphic-p)
|
|
(corfu-terminal-mode +1)))
|
|
|
|
;; Add extensions
|
|
(use-package cape
|
|
:ensure t
|
|
:defer 3
|
|
;; Bind prefix keymap providing all Cape commands under a mnemonic key.
|
|
;; Press C-c p ? to for help.
|
|
:bind ("C-c p" . cape-prefix-map) ;; Alternative keys: M-p, M-+, ...
|
|
;; Alternatively bind Cape commands individually.
|
|
;; :bind (("C-c p d" . cape-dabbrev)
|
|
;; ("C-c p h" . cape-history)
|
|
;; ("C-c p f" . cape-file)
|
|
;; ...)
|
|
:init
|
|
;; Add to the global default value of `completion-at-point-functions' which is
|
|
;; used by `completion-at-point'. The order of the functions matters, the
|
|
;; first function returning a result wins. Note that the list of buffer-local
|
|
;; completion functions takes precedence over the global list.
|
|
(add-hook 'completion-at-point-functions #'cape-dabbrev)
|
|
(add-hook 'completion-at-point-functions #'cape-file)
|
|
(add-hook 'completion-at-point-functions #'cape-elisp-block)
|
|
;; (add-hook 'completion-at-point-functions #'cape-history)
|
|
;; ...
|
|
)
|
|
|
|
;; Org-mode. ------
|
|
(use-package org
|
|
:ensure t
|
|
:hook (org-mode . visual-line-mode)
|
|
:custom
|
|
(org-ellipsis "...")
|
|
(org-sturtup-indent t)
|
|
(org-hide-emphasis-markers t))
|
|
|
|
;; (use-package mini-modeline
|
|
;; :ensure t
|
|
;; ;; :quelpa (mini-modeline :repo "kiennq/emacs-mini-modeline" :fetcher github)
|
|
;; ;; :after smart-mode-line
|
|
;; :config
|
|
;; (setq mini-modeline-display-gui-line t)
|
|
;; (setq mini-modeline-enhance-visual t)
|
|
;; (setq mini-modeline-l-format '("%e " mode-line-modified " "
|
|
;; (:eval (propertize (buffer-name)) 'face 'font-lock-constant-face)
|
|
;; "%6l:%c (%o) "
|
|
;; (:eval (unless (not vc-mode) (concat " | git:" (substring-no-properties vc-mode 5))))))
|
|
;; (setq mini-modeline-r-format '(""
|
|
;; (:eval (concat " " (symbol-name major-mode)))
|
|
;; " " mode-line-misc-info))
|
|
;; (mini-modeline-mode t))
|
|
|
|
;; Avy -----
|
|
(use-package avy
|
|
:ensure t)
|
|
|
|
;; Move Lines/Text -----
|
|
(use-package move-text
|
|
:ensure t)
|
|
(defun indent-region-advice (&rest ignored)
|
|
(let ((deactivate deactivate-mark))
|
|
(if (region-active-p)
|
|
(indent-region (region-beginning) (region-end))
|
|
(indent-region (line-beginning-position) (line-end-position)))
|
|
(setq deactivate-mark deactivate)))
|
|
(advice-add 'move-text-up :after 'indent-region-advice)
|
|
(advice-add 'move-text-down :after 'indent-region-advice)
|
|
|
|
|
|
;;; Magig ------
|
|
(use-package magit
|
|
:ensure t
|
|
:defer 0
|
|
:init
|
|
(setq magit-auto-revert-mode nil))
|
|
|
|
|
|
;; Keybindings ------
|
|
(define-key (current-global-map) [remap dired] 'dired-jump)
|
|
(define-key (current-global-map) [remap list-buffers] 'ibuffer)
|
|
(define-key (current-global-map) [remap kill-buffer] 'kill-current-buffer)
|
|
|
|
(global-set-key (kbd "C-c d d") 'kill-whole-line)
|
|
(global-set-key (kbd "C-c w s") 'visual-line-mode)
|
|
|
|
(global-set-key (kbd "S-C-<left>") 'shrink-window-horizontally)
|
|
(global-set-key (kbd "S-C-<right>") 'enlarge-window-horizontally)
|
|
(global-set-key (kbd "S-C-<down>") 'shrink-window)
|
|
(global-set-key (kbd "S-C-<up>") 'enlarge-window)
|
|
|
|
(global-set-key (kbd "C-z") 'move-text-down)
|
|
(global-set-key (kbd "C-q") 'move-text-up)
|
|
|
|
(global-set-key (kbd "C-c t c") 'avy-goto-char)
|
|
(global-set-key (kbd "C-c t w") 'avy-goto-word-0)
|
|
|
|
|
|
;;; Functions. -----
|
|
;;RecentFiles
|
|
(defun my/recentf-open-files-compl ()
|
|
(interactive)
|
|
(recentf-mode 1)
|
|
(let* ((tocpl (mapcar (lambda (x) (cons (file-name-nondirectory x) x))
|
|
recentf-list))
|
|
(fname (completing-read "Recent-file name: " tocpl nil nil)))
|
|
(when fname
|
|
(find-file (cdr (assoc-string fname tocpl))))))
|
|
(global-set-key "\C-x\C-r" 'my/recentf-open-files-compl)
|
|
|
|
;; Half page up/down
|
|
(defun my/half-page-up ()
|
|
(interactive)
|
|
;; (scroll-down-command )
|
|
(move-to-window-line-top-bottom 0)
|
|
(recenter))
|
|
(global-set-key (kbd "M-p") 'my/half-page-up)
|
|
|
|
(defun my/half-page-down ()
|
|
(interactive)
|
|
(if (eq (line-number-at-pos) (line-number-at-pos (window-start)))
|
|
;; If the cursor is at the top of the page, move it to the center
|
|
(progn
|
|
(let ((middle-line (1+ (/ (window-height) 2))))
|
|
(move-to-window-line middle-line)))
|
|
;; (scroll-up scroll-amount)
|
|
(move-to-window-line -1 )
|
|
(recenter)))
|
|
(global-set-key (kbd "M-n") 'my/half-page-down)
|
|
|
|
;; Split window and follow cursor. -----
|
|
(defun my/split-and-follow-horizontaly ()
|
|
(interactive)
|
|
(split-window-below)
|
|
(balance-windows)
|
|
(other-window 1))
|
|
(global-set-key (kbd "C-x 2") 'my/split-and-follow-horizontaly)
|
|
|
|
(defun my/split-and-follow-verticaly ()
|
|
(interactive)
|
|
(split-window-right)
|
|
(balance-windows)
|
|
(other-window 1))
|
|
(global-set-key (kbd "C-x 3") 'my/split-and-follow-verticaly)
|
|
|
|
;; Kill whole word/line
|
|
(defun my/kill-whole-word ()
|
|
(interactive)
|
|
(forward-char 1)
|
|
(backward-word)
|
|
(kill-word 1))
|
|
(global-set-key (kbd "C-c w w") 'my/kill-whole-word)
|
|
|
|
(defun my/copy-whole-line ()
|
|
(interactive)
|
|
(save-excursion
|
|
(kill-new
|
|
(buffer-substring
|
|
(point-at-bol)
|
|
(point-at-eol)))))
|
|
(global-set-key (kbd "C-c w l") 'my/copy-whole-line)
|
|
|
|
;; Duplicate Line.
|
|
(defun my/duplicate-line ()
|
|
"Duplicate current line"
|
|
(interactive)
|
|
(let ((column (- (point) (point-at-bol)))
|
|
(line (let ((s (thing-at-point 'line t)))
|
|
(if s (string-remove-suffix "\n" s) ""))))
|
|
(move-end-of-line 1)
|
|
(newline)
|
|
(insert line)
|
|
(move-beginning-of-line 1)
|
|
(forward-char column)))
|
|
(global-set-key (kbd "C-,") 'my/duplicate-line)
|