Skip to content

pedroangelo/emacs-config

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

emacs-config

My personal literate emacs configuration.

Notice that this file serves as my emacs configuration file, but also as a sort of repository for code I’ve collected. Hence, you’ll see many commented pieces of code. These are configurations which I choose not to use, but still wish to keep around.

Core

Garbage Collection

Emacs has a ridiculously low garbage collection threshold. The default value of gc-cons-threshold is 800 000 bytes, which amounts to less than 1 MB. While garbage collection is not automatically performed once the thresholds, given by gc-cons-percentage or gc-cons-threshold, are reached, it may happen at any moment. Hence, it’s possible for garbage collection to be triggered several times in a short time. This means constant waiting periods before garbage collection is finalised.

To fix these issues, increase the threshold and also force garbage collection when on idle.

;; set threshold for garbage collection at 100MB
(setq gc-cons-threshold  (* 100 1024 1024))
;; trigger garbage collection 4 seconds after emacs goes idle
(run-with-idle-timer 4 t (lambda () (garbage-collect)))

Backups

The standard Emacs configuration clutters the filesystem with extra files, leaving backups, autosaves and lockfiles everywhere. I prefer to keep my filesystem more tidy, hence I neatly store backups and autosaves in a single location. I also disable lockfiles: there’s no need for them since there’s only one user at a time.

;; enable automatic backups
(setq make-backup-files t)
;; save backup files in a specific folder (created automatically) to avoid cluttering
(setq backup-directory-alist
      `((".*" . ,(expand-file-name "emacs-backups/" temporary-file-directory))))

;; backup files by copying
;; (setq backup-by-copying t)
;; backup symlinks by copying
;; (setq backup-by-copying-when-linked t)

;; enable automatic autosaves
(setq auto-save-default t)
;; specify the regularity of autosaves
(setq auto-save-interval 20)
;; unless autosaves directory exists, create it
(unless (file-exists-p (expand-file-name "emacs-autosaves/" temporary-file-directory))
  (make-directory (expand-file-name "emacs-autosaves/" temporary-file-directory)))
;; save autosave files in a specific folder, to avoid cluttering
(setq auto-save-file-name-transforms
      `((".*" ,(expand-file-name "emacs-autosaves/" temporary-file-directory) t)))

;; do not lock files
(setq create-lockfiles nil)

Configurations

Set global configuration variables:

;; display both current line and collumn numbers for pointer
(setq column-number-mode t)
(setq line-number-mode t)

;; display box cursor
(setq-default cursor-type 'box)

;; ;; display line numbers relative to current cursor line
;; (setq display-line-numbers-type 'relative)

;; use spaces for indentation instead of tabs
(setq-default indent-tabs-mode nil)

;; ;; Do not show the startup screen.
;; (setq inhibit-startup-message t)

;; kill the whole line, including newline, if at collumn zero
;; kill up to newline if not at collumn zero
(setq kill-whole-line t)

;; Save existing clipboard text into the kill ring before replacing it.
(setq save-interprogram-paste-before-kill t)

;; do no save duplicate entries into kill ring
(setq kill-do-not-save-duplicates t)

;; default tab width set to 2 spaces
(setq-default tab-width 2)

;; wrap text at words (doesn't treat as having a newline at the end)
(setq-default word-wrap t)

;; place custom-set-variables and custom-set-faces into their own file
(setq custom-file (concat user-emacs-directory "custom.el"))
(when (file-exists-p custom-file)
(load custom-file))

Enable / disable modes:

;; ;; save previous emacs session
;; (desktop-save-mode 1)

;; disable electric-indent-mode
(electric-indent-mode -1)

;; update buffer when file changes on disk
(global-auto-revert-mode 1)

;; display line numbers
(global-display-line-numbers-mode t)

;; highlight current line
(global-hl-line-mode t)

;; ;; wrap text at words (treats as having a newline at the end)
;; (global-visual-line-mode t)

;; do not display menu bar, tool bar and scroll bar
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)

;; remember and restore the last cursor location of opened files
(save-place-mode 1)

;; display matching parenthesis
(show-paren-mode 1)

Customise key bindings:

;; unset key bind to suspend emacs
(when (display-graphic-p)
  (global-unset-key (kbd "C-z"))
  (global-unset-key (kbd "C-x C-z")))

Utilities

Custom functions:

(defun file-to-string (file)
  "Read file contents and return as string"
  (with-temp-buffer
    (insert-file-contents file)
    (buffer-string)))

(defun string-reset-width (string)
  "Remove all newline characters from string, effectively adjusting the width to
  size of string"
  (replace-regexp-in-string "\n" "" string))

(defun string-nth (n string)
  "Obtain char at the nth position in the string"
  (substring string n (+ n 1)))

;; (defun split-string-max-length (string max-length)
;;   "Split a string into substrings with a max length of max-length"
;;   (let ((new-string nil)
;;         (rest-string string))
;;     (let ((number-substrings (if (= 0 (mod (length string) max-length))
;;                                  (/ (length string) max-length)
;;                                (+ 1 (/ (length string) max-length)))))
;;       (progn
;;         (dotimes (number number-substrings)
;;           (progn
;;             (setq new-string (concat new-string
;;                                      (seq-take rest-string max-length) "\n"))
;;             (setq rest-string (seq-drop rest-string max-length))))
;;         new-string))))

(defun string-adjust-width (string width)
  "Adjust string width to width by moving newlines"
  (let* ((clean-string (replace-regexp-in-string "\n" "" string))
         (length-string (length clean-string))
         (number-lines (ceiling (/ (float length-string) width)))
         (partition-size (ceiling (/ (float length-string) number-lines))))
    (if (< length-string width)
        clean-string
      (string-join (seq-partition clean-string partition-size) "\n"))))

(setq personal-quote-list
      (split-string (file-to-string "~/MEGA/Hobbies e Interesses/Quotes") "\n"))
(setq personal-quote-list-formatted
      (mapcar
        (lambda (quote)
          (string-adjust-width quote (truncate (* (window-width) 0.95))))
        personal-quote-list))

Package Management

Instalation

Setting up package and archives

(require 'package)

;; only needed for emacs versions prior to 27
(when (< emacs-major-version 27)
  (package-initialize))

(add-to-list 'package-archives
             '("melpa" . "http://melpa.org/packages/") t)
(add-to-list 'package-archives
             '("gnu" . "https://elpa.gnu.org/packages/") t)

From the package use-package, other packages can be installed. Hence, ensure it is either already installed, or install it.

(unless (package-installed-p 'use-package)
  (unless package-archive-contents (package-refresh-contents))
  (package-install 'use-package))

use-package

Configuration for the use-package package, which allows to manage several packages more easily by isolating the configurations in a tidy way (Github):

(eval-when-compile
  ;; Following line is not needed if use-package.el is in ~/.emacs.d
  (require 'use-package))

;; automatically install packages not present already
(require 'use-package-ensure)
(setq use-package-always-ensure t)

;; ;; automatically update outdated packages
;; (use-package auto-package-update
;;   :config
;;   (setq auto-package-update-delete-old-versions t)
;;   (setq auto-package-update-hide-results t)
;;   (auto-package-update-maybe))

Libraries

(use-package dash
  :pin gnu)

(use-package seq
  :pin gnu)

(use-package s)

Interface

Splash Screen

Configurations for the dashboard package, which replaces the splash screen with a configurable dashboard (Github):

(use-package dashboard
  :init
  ;; set the title
  (setq dashboard-banner-logo-title "Emacs Dashboard")
  ;; set the banner
  (setq dashboard-startup-banner 'logo)
  ;; center content
  (setq dashboard-center-content t)
  ;; set dashboard items
  (setq dashboard-items '((bookmarks . 5)
                          (recents  . 5)))
  (use-package all-the-icons
    :if (display-graphic-p))
  ;; use all-the-icons package
  ;; don't forget to M-x all-the-icons-install-fonts
  (setq dashboard-icon-type 'all-the-icons)
  ;; add icons to the widget headings and their items
  (setq dashboard-set-heading-icons t)
  (setq dashboard-set-file-icons t)
  ;; show navigator below the banner
  (setq dashboard-set-navigator t)
  ;; show info about the packages loaded and the init time:
  (setq dashboard-set-init-info t)
  ;; Format: "(icon title help action face prefix suffix)"
  (setq dashboard-navigator-buttons
        `(;; line1
          ((,(all-the-icons-faicon "refresh" :height 1.1 :v-adjust 0.0)
            "Reload Configs" "Reload configurations from dot files"
            (lambda (&rest _) (load-file (expand-file-name "init.el" user-emacs-directory)))
            nil "" ""))))
  (setq dashboard-footer-messages personal-quote-list-formatted)
  (setq dashboard-footer-icon (all-the-icons-faicon "quote-left"
                                                    :height 1.1
                                                    :v-adjust -0.05
                                                    :face 'font-lock-keyword-face))
  :config
  (dashboard-setup-startup-hook))

Windows and Frames

Configurations for the zoom package, which automatically resizes windows according to a given ration, giving greater focus on the currently focused window (Github):

(use-package zoom
  :config
  (zoom-mode t)
  ;; resize windows according to the golden ratio
  (custom-set-variables '(zoom-size '(0.618 . 0.618))))

Themes

Configurations for the solarized-theme package, which enables automatic theme switching according to time of day (Github):

(use-package solarized-theme)

Configurations for the circadian package, which enables automatic theme switching according to time of day (Github):

(use-package circadian
  :config
  (setq calendar-latitude 41.1)
  (setq calendar-longitude -8.7)
  (setq circadian-themes '((:sunrise . solarized-light)
                           ("5:00" . solarized-light)
                           (:sunset . solarized-dark)
                           ("18:30" . solarized-dark)))
  (circadian-setup))

Focus Enhancing and Distraction Avoiding

Configurations for the dimmer package, which automatically dims all but the currently focused window (Github):

(use-package dimmer
  :config
  (dimmer-mode t)
  ;; set dimmer to only apply to foreground
  (setq dimmer-adjustment-mode :foreground)
  ;; set dimmer to dim 35%
  (setq dimmer-fraction 0.35))

Help

Configurations for the helpful package, which enhances standard help functions (Github):

(use-package helpful
  :config
  (global-set-key (kbd "C-h f") #'helpful-callable)
  (global-set-key (kbd "C-h v") #'helpful-variable)
  (global-set-key (kbd "C-h k") #'helpful-key)
  (global-set-key (kbd "C-h x") #'helpful-command)
  (global-set-key (kbd "C-c C-d") #'helpful-at-point))

Editing

Spell Checking

For spell checking, I use flyspell and aspell. However, flyspell didn’t work out of the box, due to Flatpak’s containment environment. I installed Emacs via Snap instead and it worked.

Configurations for the flyspell package, which provides on-the-fly spell checking:

(require 'flyspell)

;; use the aspell spell checker instead of ispell
(setq ispell-program-name "aspell")
;; flyspell provides an issue message for every word it analyses
;; to avoid a slowdown, disable this feature
(setq flyspell-issue-message-flag nil)

;; set the default dictionary to British English
(setq ispell-dictionary "en_GB")
;; set the default dictionary to Portuguese
;; (setq ispell-dictionary "pt_PT")

;; enable flyspell in major modes
(add-hook 'LaTeX-mode-hook 'flyspell-mode)
(add-hook 'text-mode-hook 'flyspell-mode)
(add-hook 'prog-mode-hook 'flyspell-prog-mode)

;; run flyspell on the entire buffer after flyspell minor mode is enabled
(add-hook 'flyspell-mode-hook #'flyspell-buffer)

Now that spell checking is configured, let’s allow for spell checking of several languages at the same time. For this, I’m using the guess-language package.

Configuration for the guess-language package, which automatically detects the language being typed and switches spell checker (Github):

(use-package guess-language
  :ensure t
  :init
  ;; guess language in major modes
  (add-hook 'LaTeX-mode-hook #'guess-language-mode)
  (add-hook 'text-mode-hook #'guess-language-mode)
  (add-hook 'prog-mode-hook #'guess-language-mode)
  :config
  ;; guess languages between portuguese and british
  (setq guess-language-languages '(en pt))
  (setq guess-language-langcodes
        '((en . ("en_GB" "british" "🇬🇧" "English"))
          (pt . ("pt_PT" "portuguese" "🇵🇹" "Português"))))
  ;; set the minimal length a paragraph needs to have before guess-language-mode changes to its language
  (setq guess-language-min-paragraph-length 35)
  ;; automatically run flyspell-buffer when languages change
  ;; (add-hook 'guess-language-after-detection-functions
  ;;           (lambda (lang beg end)
  ;;             (flyspell-region beg end)))
  )

Note that guess-language inspects a paragraph in order to detect language. Hence, the texts in different languages must have at least a empty line between them.

Text Highlight

Configurations for the rainbow-mode package, which sets the background colour of strings to match the string’s colour name (Github):

(use-package rainbow-mode
  :hook (emacs-lisp-mode text-mode lisp-mode))

Indentation

Configurations for the aggressive-indent package, which automatically inserts indentation according to the language and scope (Github):

(use-package aggressive-indent
  :config
  ;; (add-to-list 'aggressive-indent-excluded-modes 'emacs-lisp-mode)
  (global-aggressive-indent-mode 1))

Configurations for the highlight-indent-guides package, which shown indentation guides (Github):

(use-package highlight-indent-guides
  :config
  (add-hook 'prog-mode-hook 'highlight-indent-guides-mode)
  (setq highlight-indent-guides-method 'character))

Auto Completion

Configurations for the company package, which provides autocompletion tooltips (Github webpage):

(use-package company
  :pin gnu
  :config
  ;; (setq company-idle-delay nil)
  (setq company-dabbrev-downcase nil)
  (add-hook 'after-init-hook 'global-company-mode))

Text Folding

Configurations for the origami package, which allows code blocks to be folded (Github):

(use-package origami
  :requires (dash s)
  :config
  (global-origami-mode))

Languages

Haskell

Configurations for the haskell-mode package, which provides Haskell keyword highlighting (Github):

(use-package haskell-mode)

Markdown

Configurations for the markdown-mode package, which provides markdown keyword highlighting (Github):

(use-package markdown-mode
  :mode (("README\\.md\\'" . gfm-mode)
         ("TODO\\.md\\'" . gfm-mode)
         ("\\.md\\'" . markdown-mode)
         ("\\.markdown\\'" . markdown-mode))
  :init (setq markdown-command "pandoc"))

Latex

;; show whitespaces as dots
;; (add-hook 'latex-mode-hook 'whitespace-mode)

Miscellaneous

Org-mode

;; prevent truncating lines in org mode; similar to word-wrap
(setq org-startup-truncated nil)

;; open files with unfolded headings
(setq org-startup-folded nil)

Whisper

Configurations for the whisper speech-to-text engine:

(add-to-list 'load-path (expand-file-name "packages/whisper" user-emacs-directory))

(use-package whisper
  :load-path "~/.emacs.d/packages/whisper"
  :bind ("C-H-r" . whisper-run)
  :config
  (setq whisper-install-directory "~/.local/lib"
        whisper-language "en"
        whisper-model "base" ;; model options: tiny, base, small, medium, large
        whisper-translate nil
        whisper-enable-speed-up nil))

Releases

No releases published

Packages

No packages published