#+TITLE: Emacs Configuration #+AUTHOR: TlasT #+STARTUP: showeverything #+OPTIONS: toc:3 * TABLE OF CONTENTS :toc: - [[#startup-configuration][Startup Configuration]] - [[#elpaca-package-manager][Elpaca (Package Manager)]] - [[#evil-mode][Evil Mode]] - [[#keybindings][Keybindings]] - [[#helper-functions][Helper functions]] - [[#buffer-move][buffer-move]] - [[#reload-emacs][Reload Emacs]] - [[#graphical-configuration][Graphical configuration]] - [[#disable-menubar-toolbars-and-scrollbars][Disable Menubar, Toolbars and Scrollbars]] - [[#display-line-numbers-and-truncated-lines][Display Line Numbers and Truncated Lines]] - [[#fonts][Fonts]] - [[#setting-the-font-face][Setting the Font Face]] - [[#theme][Theme]] - [[#org-mode][ORG Mode]] - [[#enabling-table-of-contents][Enabling Table of Contents]] - [[#enabling-org-bullets][Enabling Org Bullets]] - [[#source-code-block-tag-expansion][Source Code Block Tag Expansion]] - [[#shell][Shell]] - [[#default-shell][Default shell]] - [[#eshell][Eshell]] - [[#packages][Packages]] - [[#sudo-edit][Sudo edit]] - [[#which-key][Which-Key]] - [[#all-the-icons][All The Icons]] - [[#rainbow-mode][Rainbow Mode]] - [[#ivy-counsel][IVY (Counsel)]] - [[#projectile][Projectile]] - [[#dashboard][Dashboard]] - [[#flycheck][Flycheck]] - [[#company][COMPANY]] * Startup Configuration ** Elpaca (Package Manager) #+begin_src emacs-lisp (defvar elpaca-installer-version 0.6) (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 :files (:defaults (: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 (call-process "git" nil buffer t "clone" (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))) (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)) ;; Install use-package support (elpaca elpaca-use-package ;; Enable :elpaca use-package keyword. (elpaca-use-package-mode) ;; Assume :elpaca t unless otherwise specified. (setq elpaca-use-package-by-default t)) ;; Block until current queue processed. (elpaca-wait) ;;When installing a package which modifies a form used at the top-level ;;(e.g. a package which adds a use-package key word), ;;use `elpaca-wait' to block until that package has been installed/configured. ;;For example: ;;(use-package general :demand t) ;;(elpaca-wait) ;;Turns off elpaca-use-package-mode current declartion ;;Note this will cause the declaration to be interpreted immediately (not deferred). ;;Useful for configuring built-in emacs features. ;;(use-package emacs :elpaca nil :config (setq ring-bell-function #'ignore)) ;; Don't install anything. Defer execution of BODY ;;(elpaca nil (message "deferred")) #+end_src ** Evil Mode #+begin_src emacs-lisp ;; Expands to: (elpaca evil (use-package evil :demand t)) (use-package evil :init ;; tweak evil's configuration before loading it (setq evil-want-integration t) ;; This is optional since it's already set to t by default. (setq evil-want-keybinding nil) (setq evil-vsplit-window-right t) (setq evil-split-window-below t) (evil-mode)) (use-package evil-collection :after evil :config (setq evil-collection-mode-list '(dashboard dired ibuffer)) (evil-collection-init)) (use-package evil-tutor) #+end_src ** Keybindings #+begin_src emacs-lisp (use-package general :config (general-evil-setup) ;; set up 'SPC' as the global leader key (general-create-definer user/leader-keys :states '(normal insert visual emacs) :keymaps 'override :prefix "SPC" ;; set leader :global-prefix "M-SPC") ;; access leader in insert mode (user/leader-keys "SPC" '(counsel-M-x :wk "Counsel M-x") "." '(find-file :wk "Find file") "f c" '((lambda () (interactive) (find-file "~/.config/emacs/config.org")) :wk "Edit emacs config") "f r" '(counsel-recentf :wk "Find recent files") "f w" '(evil-write :wk "Write current buffer") "f q" '(evil-quit :wk "Write current buffer") "TAB TAB" '(comment-line :wk "Comment lines")) (user/leader-keys "b" '(:ignore t :wk "buffer") "b b" '(switch-to-buffer :wk "Switch buffer") "b i" '(ibuffer :wk "Ibuffer") "b k" '(kill-this-buffer :wk "Kill this buffer") "b n" '(next-buffer :wk "Next buffer") "b p" '(previous-buffer :wk "Previous buffer") "b r" '(revert-buffer :wk "Reload buffer")) (user/leader-keys "e" '(:ignore t :wk "Eshell/Evaluate") "e b" '(eval-buffer :wk "Evaluate elisp in buffer") "e d" '(eval-defun :wk "Evaluate defun containing or after point") "e e" '(eval-expression :wk "Evaluate and elisp expression") "e h" '(counsel-esh-history :which-key "Eshell history") "e l" '(eval-last-sexp :wk "Evaluate elisp expression before point") "e r" '(eval-region :wk "Evaluate elisp in region") "e s" '(eshell :which-key "Eshell")) (user/leader-keys "h" '(:ignore t :wk "Help") "h f" '(describe-function :wk "Describe function") "h v" '(describe-variable :wk "Describe variable") ;;"h r r" '((lambda () (interactive) (load-file "~/.config/emacs/init.el")) :wk "Reload emacs config")) "h r r" '(reload-init-file :wk "Reload emacs config")) (user/leader-keys "t" '(:ignore t :wk "Toggle") "t l" '(display-line-numbers-mode :wk "Toggle line numbers") "t t" '(visual-line-mode :wk "Toggle truncated lines") "t v" '(shell :wk "open shell")) (user/leader-keys "w" '(:ignore t :wk "Windows") ;; Window splits "w c" '(evil-window-delete :wk "Close window") "w n" '(evil-window-new :wk "New window") "w s" '(evil-window-split :wk "Horizontal split window") "w v" '(evil-window-vsplit :wk "Vertical split window") ;; Window motions "w h" '(evil-window-left :wk "Window left") "w j" '(evil-window-down :wk "Window down") "w k" '(evil-window-up :wk "Window up") "w l" '(evil-window-right :wk "Window right") "w w" '(evil-window-next :wk "Goto next window") ;; Move Windows "w H" '(buf-move-left :wk "Buffer move left") "w J" '(buf-move-down :wk "Buffer move down") "w K" '(buf-move-up :wk "Buffer move up") "w L" '(buf-move-right :wk "Buffer move right")) ;; org mode (user/leader-keys "m" '(:ignore t :wk "Org") "m a" '(org-agenda :wk "Org agenda") "m e" '(org-export-dispatch :wk "Org export dispatch") "m i" '(org-toggle-item :wk "Org toggle item") "m t" '(org-todo :wk "Org todo") "m B" '(org-babel-tangle :wk "Org babel tangle") "m T" '(org-todo-list :wk "Org todo list")) (user/leader-keys "m b" '(:ignore t :wk "Tables") "m b -" '(org-table-insert-hline :wk "Insert hline in table")) (user/leader-keys "m d" '(:ignore t :wk "Date/deadline") "m d t" '(org-time-stamp :wk "Org time stamp")) (user/leader-keys "p" '(projectile-command-map :wk "Projectile")) ) #+end_src Zooming in and out #+begin_src emacs-lisp (global-set-key (kbd "C-=") 'text-scale-increase) (global-set-key (kbd "C--") 'text-scale-decrease) (global-set-key (kbd "") 'text-scale-increase) (global-set-key (kbd "") 'text-scale-decrease) #+end_src * Helper functions ** buffer-move Creating some functions to allow us to easily move windows (splits) around. The following block of code was taken from buffer-move.el found on the EmacsWiki: https://www.emacswiki.org/emacs/buffer-move.el #+begin_src emacs-lisp (require 'windmove) ;;;###autoload (defun buf-move-up () "Swap the current buffer and the buffer above the split. If there is no split, ie now window above the current one, an error is signaled." ;; "Switches between the current buffer, and the buffer above the ;; split, if possible." (interactive) (let* ((other-win (windmove-find-other-window 'up)) (buf-this-buf (window-buffer (selected-window)))) (if (null other-win) (error "No window above this one") ;; swap top with this one (set-window-buffer (selected-window) (window-buffer other-win)) ;; move this one to top (set-window-buffer other-win buf-this-buf) (select-window other-win)))) ;;;###autoload (defun buf-move-down () "Swap the current buffer and the buffer under the split. If there is no split, ie now window under the current one, an error is signaled." (interactive) (let* ((other-win (windmove-find-other-window 'down)) (buf-this-buf (window-buffer (selected-window)))) (if (or (null other-win) (string-match "^ \\*Minibuf" (buffer-name (window-buffer other-win)))) (error "No window under this one") ;; swap top with this one (set-window-buffer (selected-window) (window-buffer other-win)) ;; move this one to top (set-window-buffer other-win buf-this-buf) (select-window other-win)))) ;;;###autoload (defun buf-move-left () "Swap the current buffer and the buffer on the left of the split. If there is no split, ie now window on the left of the current one, an error is signaled." (interactive) (let* ((other-win (windmove-find-other-window 'left)) (buf-this-buf (window-buffer (selected-window)))) (if (null other-win) (error "No left split") ;; swap top with this one (set-window-buffer (selected-window) (window-buffer other-win)) ;; move this one to top (set-window-buffer other-win buf-this-buf) (select-window other-win)))) ;;;###autoload (defun buf-move-right () "Swap the current buffer and the buffer on the right of the split. If there is no split, ie now window on the right of the current one, an error is signaled." (interactive) (let* ((other-win (windmove-find-other-window 'right)) (buf-this-buf (window-buffer (selected-window)))) (if (null other-win) (error "No right split") ;; swap top with this one (set-window-buffer (selected-window) (window-buffer other-win)) ;; move this one to top (set-window-buffer other-win buf-this-buf) (select-window other-win)))) #+end_src ** Reload Emacs This is just an example of how to create a simple function in Emacs. Use this function to reload Emacs after adding changes to the config. Yes, I am loading the user-init-file twice in this function, which is a hack because for some reason, just loading the user-init-file once does not work properly. #+begin_src emacs-lisp (defun reload-init-file () (interactive) (load-file user-init-file) (load-file user-init-file)) #+end_src * Graphical configuration ** Disable Menubar, Toolbars and Scrollbars #+begin_src emacs-lisp (menu-bar-mode -1) (tool-bar-mode -1) (scroll-bar-mode -1) #+end_src ** Display Line Numbers and Truncated Lines #+begin_src emacs-lisp (global-display-line-numbers-mode 1) (global-visual-line-mode t) #+end_src ** Fonts Defining the various fonts that Emacs will use. ** Setting the Font Face #+begin_src emacs-lisp (set-face-attribute 'default nil :font "JetBrains Mono" :height 105 :weight 'medium) (set-face-attribute 'variable-pitch nil :font "Ubuntu" :height 115 :weight 'medium) (set-face-attribute 'fixed-pitch nil :font "JetBrains Mono" :height 105 :weight 'medium) ;; Makes commented text and keywords italics. ;; This is working in emacsclient but not emacs. ;; Your font must have an italic face available. (set-face-attribute 'font-lock-comment-face nil :slant 'italic) (set-face-attribute 'font-lock-keyword-face nil :slant 'italic) ;; This sets the default font on all graphical frames created after restarting Emacs. ;; Does the same thing as 'set-face-attribute default' above, but emacsclient fonts ;; are not right unless I also add this method of setting the default font. (add-to-list 'default-frame-alist '(font . "JetBrains Mono-11")) ;; Uncomment the following line if line spacing needs adjusting. (setq-default line-spacing 0.12) #+end_src ** Theme How to make thet theme work even in daemon mode: (https://stackoverflow.com/questions/18904529/after-emacs-deamon-i-can-not-see-new-theme-in-emacsclient-frame-it-works-fr) #+begin_src emacs-lisp (add-to-list 'custom-theme-load-path "~/.config/emacs/themes/") (defvar my:theme 'nord) (defvar my:theme-window-loaded nil) (defvar my:theme-terminal-loaded nil) (if (daemonp) (add-hook 'after-make-frame-functions(lambda (frame) (select-frame frame) (if (window-system frame) (unless my:theme-window-loaded (if my:theme-terminal-loaded (enable-theme my:theme) (load-theme my:theme t)) (setq my:theme-window-loaded t)) (unless my:theme-terminal-loaded (if my:theme-window-loaded (enable-theme my:theme) (load-theme my:theme t)) (setq my:theme-terminal-loaded t))))) (progn (load-theme my:theme t) (if (display-graphic-p) (setq my:theme-window-loaded t) (setq my:theme-terminal-loaded t)))) #+end_src * ORG Mode ** Enabling Table of Contents #+begin_src emacs-lisp (use-package toc-org :commands toc-org-enable :init (add-hook 'org-mode-hook 'toc-org-enable)) #+end_src ** Enabling Org Bullets Org-bullets gives us attractive bullets rather than asterisks. #+begin_src emacs-lisp (add-hook 'org-mode-hook 'org-indent-mode) (use-package org-bullets) (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))) #+end_src ** Source Code Block Tag Expansion Org-tempo is not a separate package but a module within org that can be enabled. Org-tempo allows for ' to complete or to complete the common part. #+begin_src emacs-lisp (use-package company :defer 2 :diminish :custom (company-begin-commands '(self-insert-command)) (company-idle-delay .1) (company-minimum-prefix-length 2) (company-show-numbers t) (company-tooltip-align-annotations 't) (global-company-mode t)) (use-package company-box :after company :diminish :hook (company-mode . company-box-mode)) #+end_src