#+STARTUP: overview #+TITLE: My Emacs #+CREATOR: Laurens Miers #+LANGUAGE: en [[./img/dash_logo.png]] * Elpaca #+begin_src emacs-lisp (defvar elpaca-installer-version 0.7) (defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory)) (defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory)) (defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory)) (defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git" :ref nil :depth 1 :files (:defaults "elpaca-test.el" (:exclude "extensions")) :build (:not elpaca--activate-package))) (let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory)) (build (expand-file-name "elpaca/" elpaca-builds-directory)) (order (cdr elpaca-order)) (default-directory repo)) (add-to-list 'load-path (if (file-exists-p build) build repo)) (unless (file-exists-p repo) (make-directory repo t) (when (< emacs-major-version 28) (require 'subr-x)) (condition-case-unless-debug err (if-let ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*")) ((zerop (apply #'call-process `("git" nil ,buffer t "clone" ,@(when-let ((depth (plist-get order :depth))) (list (format "--depth=%d" depth) "--no-single-branch")) ,(plist-get order :repo) ,repo)))) ((zerop (call-process "git" nil buffer t "checkout" (or (plist-get order :ref) "--")))) (emacs (concat invocation-directory invocation-name)) ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch" "--eval" "(byte-recompile-directory \".\" 0 'force)"))) ((require 'elpaca)) ((elpaca-generate-autoloads "elpaca" repo))) (progn (message "%s" (buffer-string)) (kill-buffer buffer)) (error "%s" (with-current-buffer buffer (buffer-string)))) ((error) (warn "%s" err) (delete-directory repo 'recursive)))) (unless (require 'elpaca-autoloads nil t) (require 'elpaca) (elpaca-generate-autoloads "elpaca" repo) (load "./elpaca-autoloads"))) (add-hook 'after-init-hook #'elpaca-process-queues) (elpaca `(,@elpaca-order)) #+end_src #+begin_src emacs-lisp ;; Install use-package support (elpaca elpaca-use-package ;; Enable use-package :ensure support for Elpaca. (elpaca-use-package-mode) ) #+end_src * General config ** Delete trailing whitespaces #+BEGIN_SRC emacs-lisp (add-hook 'before-save-hook 'delete-trailing-whitespace) #+END_SRC ** Save history and recent files #+begin_src emacs-lisp ;; The built-in `savehist-mode' saves minibuffer histories. Vertico ;; can then use that information to put recently selected options at ;; the top. ;; ;; Further reading: https://protesilaos.com/emacs/dotemacs#h:25765797-27a5-431e-8aa4-cc890a6a913a (savehist-mode 1) ;; The built-in `recentf-mode' keeps track of recently visited files. ;; You can then access those through the `consult-buffer' interface or ;; with `recentf-open'/`recentf-open-files'. ;; ;; I do not use this facility, because the files I care about are ;; either in projects or are bookmarked. (recentf-mode 1) #+end_src ** Yes-or-no Because I'm lazy, important yes-or-no questions can be answered with y-or-n: #+begin_src emacs-lisp (defalias 'yes-or-no-p 'y-or-n-p) #+end_src ** FIDO Use Fake-ido as minibuffer completion system, more info here: https://www.gnu.org/software/emacs/manual/html_node/emacs/Icomplete.html #+begin_src emacs-lisp (fido-vertical-mode 1) #+end_src ** Switch windows #+begin_src emacs-lisp (global-set-key (kbd "M-o") 'other-window) #+end_src ** Maximize at startup More info : https://www.emacswiki.org/emacs/FullScreen #+begin_src emacs-lisp (push '(fullscreen . maximized) default-frame-alist) #+end_src ** ibuffer Use list-buffers bigger brother. #+begin_src emacs-lisp (global-set-key [remap list-buffers] 'ibuffer) #+end_src ** Mark #+begin_src emacs-lisp (global-set-key (kbd "M-SPC") 'mark-word) #+end_src ** Isearch Display number of matches: #+begin_src emacs-lisp (setq-default isearch-lazy-count t) #+end_src Reference that might be interesting for later: https://endlessparentheses.com/leave-the-cursor-at-start-of-match-after-isearch.html ** Sudo file #+begin_src emacs-lisp (defun sudo () "Use TRAMP to `sudo' the current buffer." (interactive) (when buffer-file-name (find-alternate-file (concat "/sudo:root@localhost:" buffer-file-name) ) ) ) #+end_src ** Abbrev #+begin_src emacs-lisp (global-set-key [remap dabbrev-expand] 'hippie-expand) #+end_src ** Zap #+begin_src emacs-lisp (global-set-key (kbd "M-S-z") 'zap-up-to-char) #+end_src ** Spell checking Look into customizing the 'ispell' group. #+begin_src emacs-lisp (add-hook 'prog-mode-hook 'flyspell-prog-mode) #+end_src * Dired #+begin_src emacs-lisp (require 'dired-x) #+end_src * Whole-line-or-region Source: https://github.com/purcell/whole-line-or-region Operate on the current line if no region is active. #+begin_src emacs-lisp (use-package whole-line-or-region :ensure t :config (whole-line-or-region-global-mode 1) ) #+end_src * imenu ** Flatten #+begin_src emacs-lisp (use-package flimenu :ensure t :config (flimenu-global-mode 1) ) (global-set-key (kbd "M-i") 'imenu) #+end_src * Terminal ** Toggle between char- and line-mode Courtesy goes to https://joelmccracken.github.io/entries/switching-between-term-mode-and-line-mode-in-emacs-term/ #+BEGIN_SRC emacs-lisp (require 'term) (defun jnm/term-toggle-mode () "Toggles term between line mode and char mode" (interactive) (if (term-in-line-mode) (term-char-mode) (term-line-mode))) (define-key term-mode-map (kbd "C-c C-j") 'jnm/term-toggle-mode) (define-key term-mode-map (kbd "C-c C-k") 'jnm/term-toggle-mode) (define-key term-raw-map (kbd "C-c C-j") 'jnm/term-toggle-mode) (define-key term-raw-map (kbd "C-c C-k") 'jnm/term-toggle-mode) #+END_SRC For the keybindings, we have to defien them in both raw and line mode. From the help page of term mode: If you define custom keybindings, make sure to assign them to the correct keymap (or to both): use ‘term-raw-map’ in raw mode and ‘term-mode-map’ in line mode. * Theme #+BEGIN_SRC emacs-lisp (use-package monokai-theme :ensure t :init (load-theme 'monokai t) ) #+END_SRC * Dashboard #+begin_src emacs-lisp (use-package dashboard :ensure t :config (add-hook 'elpaca-after-init-hook #'dashboard-insert-startupify-lists) (add-hook 'elpaca-after-init-hook #'dashboard-initialize) (dashboard-setup-startup-hook)) #+end_src * Hydra Install and wait for hydra to be available since we are using it in this init.el : #+begin_src emacs-lisp (use-package hydra :ensure (:wait t) ) #+end_src ** Text zoom #+begin_src emacs-lisp (defhydra hydra-zoom (global-map "") "zoom" ("g" text-scale-increase "in") ("l" text-scale-decrease "out") ) #+end_src * Programming ** Eglot #+BEGIN_SRC emacs-lisp (use-package eglot :ensure t :defer t ;; This doesn't work for some reason, workaround below ;;:hook (prog-mode . eglot-ensure) ;; :config ;; (add-hook 'prog-mode-hook 'eglot-ensure) ) #+END_SRC Workaround to enable eglot in all programming modes: #+BEGIN_SRC emacs-lisp (add-hook 'prog-mode-hook 'eglot-ensure) #+END_SRC ** Yasnippet #+BEGIN_SRC emacs-lisp (use-package yasnippet :ensure t :config (yas-reload-all) (add-hook 'prog-mode-hook 'yas-minor-mode) ) #+END_SRC ** Magit *** Transient Magit depends on this and it seems it's not installed as a dependency, so install it explicitly. #+BEGIN_SRC emacs-lisp (use-package transient :ensure t ) #+END_SRC *** Core #+BEGIN_SRC emacs-lisp (use-package magit :ensure t ) #+END_SRC ** Smartparens Smart minor-mode to deal with pairs. https://github.com/Fuco1/smartparens #+BEGIN_SRC emacs-lisp (use-package smartparens :ensure t :bind ("C-M-w" . sp-copy-sexp) :hook (prog-mode text-mode markdown-mode) :config (require 'smartparens-config) ) #+END_SRC * Multiple cursors #+BEGIN_SRC emacs-lisp (use-package multiple-cursors :ensure t :bind ("C-x r a" . mc/edit-beginnings-of-lines) ("C-x r e" . mc/edit-ends-of-lines) ("C->" . mc/mark-next-like-this) ("C-<" . mc/mark-previous-like-this) ("C-c C->" . mc/mark-all-like-this) ) #+END_SRC * Comment-dwim-2 Replacement for built-in =comment-dwim=, more comment features. https://github.com/remyferre/comment-dwim-2 #+BEGIN_SRC emacs-lisp (use-package comment-dwim-2 :ensure t :config (global-set-key (kbd "M-;") 'comment-dwim-2) ) #+END_SRC * Projectile #+BEGIN_SRC emacs-lisp (use-package projectile :ensure t :config (setq projectile-indexing-method 'alien) (setq projectile-enable-caching t) (define-key projectile-mode-map (kbd "C-x p") 'projectile-command-map) (projectile-mode +1) ) * Custom ** Save symbol at point #+BEGIN_SRC emacs-lisp (defun myrmi/save-symbol-at-point () "Make symbol at point the latest kill in the kill ring." (interactive) (let ((symbol (thing-at-point 'symbol))) (when symbol (kill-new symbol)))) (global-set-key (kbd "C-M-w") 'myrmi/save-symbol-at-point) #+END_SRC