GNU Emacs configuration file
This repository contains my (Bryan Frimin) Emacs configuration. If you find a bug or have any question, feel free to open a Github issue or to contact me by email. Please note that I do not currently review or accept any contribution.
First change default Emacs memory management, I’ve a modern computer not an Apple II.
(setq read-process-output-max (* 1024 1024)) ; 1MB instead of 4KB
(setq gc-cons-threshold 100000000) ; 100MB instead of 800KB
Use gls
instead of ls
on BSD system.
(if (eq system-type 'berkeley-unix)
(progn (setq insert-directory-program "/usr/local/bin/gls")))
Configure font and font size.
(face-spec-set 'default '((t :font "NotoMono Nerd Font")))
(set-face-attribute 'default nil :height 115)
This package is a minor mode to set background color to strings that match color name.
(use-package rainbow-mode
:straight t
:config
(setq rainbow-ansi-colors nil)
(setq rainbow-x-colors nil))
Add a newline character when visiting or saving a buffer relevance.
(setq mode-require-final-newline 'visit-save)
Keep code file clean.
(add-hook 'before-save-hook 'whitespace-cleanup)
Highligh keywords that are normally used in code comments.
(use-package hl-todo
:straight t
:config
(setq hl-todo-keyword-faces
'(("TODO" . "#FF0000")
("DEBUG" . "#1E90FF")
("XXX" . "#1E90FF")))
:hook (prog-mode-hook . hl-todo-mode))
Ensures buffers are updated whenever the file changes. A change can happen externally or by some other tool inside of Emacs.
(setq auto-revert-verbose t)
(global-auto-revert-mode)
The standard line lengh is 80 characters. Having something less allows such things like quoting text, indent, etc.
(setq-default fill-column 72)
(global-display-fill-column-indicator-mode)
Shortcut to avoid typing yes
or no
each time.
(defalias 'yes-or-no-p 'y-or-n-p)
Turn off annoying bell.
(setq ring-bell-function 'ignore)
Turns off Indent Tabs mode.
(setq-default indent-tabs-mode nil)
Enable line number mode.
(setq column-number-mode t)
Setting custom file.
(setq custom-file (concat user-emacs-directory "custom.el"))
Enable ANSI color in the compilation mode.
(defun gearnode/compilation-mode-colorize-output ()
(read-only-mode -1)
(unwind-protect
(let ((start compilation-filter-start)
(end (point)))
(ansi-color-apply-on-region start end))
(read-only-mode 1)))
(use-package compilation-mode
:straight nil
:init
(require 'ansi-color)
:config
(setq compilation-scroll-output t)
:hook
((compilation-filter-hook . gearnode/compilation-mode-colorize-output)))
Disable menu bar
, toolbar
and scrollbar
.
(menu-bar-mode -1)
(toggle-scroll-bar -1)
(tool-bar-mode -1)
Emacs history and state
This sections contains configuration for Emacs state and history management.
Remember where the cursor is in any given file.
(setq save-place-file "~/.emacs.d/saveplace")
(setq save-place-forget-unreadable-file t)
(save-place-mode 1)
Keep Emacs opened buffers after crash or kill.
(setq desktop-auto-save-timeout 300)
(setq desktop-dirname "~/.emacs.d/")
(setq desktop-base-file-name "desktop")
(setq desktop-files-not-to-save nil)
(setq desktop-globals-to-clean nil)
(setq desktop-load-locked-desktop t)
(setq desktop-missing-file-warning nil)
(setq desktop-restore-eager 0)
(setq desktop-restore-frames nil)
(setq desktop-save 'ask-if-new)
(desktop-save-mode 1)
Ensure Emacs starts in the *scratch*
buffer.
(setq initial-buffer-choice t)
(setq inhibit-startup-echo-area-message "gearnode")
(setq inhibit-startup-screen t)
(setq inhibit-startup-buffer-menu t)
Configure Emacs backup files to:
- not pollute the current working directory with emacs backup files.
- enable backup on versioned file.
(setq backup-by-copying t)
(setq version-control t)
(setq delete-old-versions t)
(setq kept-new-versions 10)
(setq kept-old-versions 5)
;; By default, Emacs never backs up versioned file.
(setq vc-make-backup-files t)
(setq backup-directory-alist '(("" . "~/.emacs.d/backup/per-save")))
(defun gearnode/force-backup-of-buffer ()
;; Make a special "per session" backup at the first save of each
;; emacs session.
(when (not buffer-backed-up)
;; Override the default parameters for per-session backups.
(let ((backup-directory-alist '(("" . "~/.emacs.d/backup/per-session")))
(kept-new-versions 3))
(backup-buffer)))
;; Make a "per save" backup on each save. The first save results in
;; both a per-session and a per-save backup, to keep the numbering
;; of per-save backups consistent.
(let ((buffer-backed-up nil))
(backup-buffer)))
(add-hook 'before-save-hook 'gearnode/force-backup-of-buffer)
(setq savehist-file "~/.emacs.d/savehist")
(setq history-length 1000)
(setq history-delete-duplicates t)
(setq savehist-save-minibuffer-history t)
(add-hook 'after-init-hook 'savehist-mode)
Use VS Code theme.
(use-package vscode-dark-plus-theme
:straight (:host github :repo "ianyepan/vscode-dark-plus-emacs-theme" :branch "master")
:ensure t
:config
(load-theme 'vscode-dark-plus t))
Git
Emacs version control seems nice, but does not wrap Git as Magit do. Because I mainly works with Git I use magit instead of VC.
(use-package magit
:straight t
:config
(setq magit-log-margin '(t "%F %R" magit-log-margin-width t 18))
:bind
("C-c g" . magit-status))
Configure git-commit
to follow my commit style
(use-package git-commit
:config
(setq git-commit-summary-max-length 50)
(setq git-commit-known-pseudo-headers
'("Signed-off-by"
"Modified-by"
"Cc"
"Suggested-by"
"Reported-by"))
(setq git-commit-style-convention-checks
'(non-empty-second-line
overlong-summary-line)))
(use-package pdf-tools
:straight t
:mode
("\\.pdf\\'" . pdf-view-mode)
:config
(setq-default pdf-view-display-size 'fit-page))
Web browser
I do not use Emacs has web browser but use the web browser binding to transform HTML email content in text one.
(use-package w3m
:straight t
:config
(setq w3m-user-agent "42")
(setq w3m-add-user-agent t)
(setq w3m-default-save-directory "~/Download")
(setq w3m-fill-column 72)
(setq w3m-default-display-inline-images t))
Open link in new Firefox tab.
(setq browse-url-browser-function 'browse-url-firefox)
(setq browse-url-new-window-flag t)
(setq browse-url-firefox-new-window-is-tab t)
GNUS
This section contains my GNUS configuration.
Bind C-c m
to open GNUS.
(global-set-key (kbd "C-c m") 'gnus)
Style
A bit of frontend to have cleaner interface.
(setq gnus-use-full-window nil)
(setq gnus-summary-line-format
(concat "%U%R %~(max-right 17)~(pad-right 17)&user-date; "
"%~(max-right 20)~(pad-right 20)f %B%s\n"))
(setq gnus-user-date-format-alist '((t . "%d.%m.%Y %H:%M"))
gnus-sum-thread-tree-false-root ""
gnus-sum-thread-tree-indent " "
gnus-sum-thread-tree-root ""
gnus-sum-thread-tree-leaf-with-other "├─≻"
gnus-sum-thread-tree-single-leaf "└─≻"
gnus-sum-thread-tree-vertical "│")
(setq gnus-summary-thread-gathering-function
'gnus-gather-threads-by-subject)
(setq gnus-thread-sort-functions
'(gnus-thread-sort-by-number
gnus-thread-sort-by-total-score))
(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)
Mailboxes
Configure mailboxes.
(setq user-mail-address "bryan@frimin.fr")
(setq user-full-name "Bryan Frimin")
(setq message-user-fqdn "workstation.frimin.fr")
(setq gnus-select-method '(nnnil nil))
(setq gnus-secondary-select-methods
'((nntp "news.gwene.org")
(nnimap "frimin"
(nnimap-address "imap.frimin.fr")
(nnimap-server-port 993)
(nnimap-stream ssl)
(nnir-search-engine imap)
(nnimap-inbox "INBOX")
(nnmail-expiry-target
"nnimap+frimin:Trash")
(nnmail-expiry-wait immediate))
(nnimap "gmail"
(nnimap-address "imap.gmail.com")
(nnimap-server-port 993)
(nnimap-stream ssl)
(nnir-search-engine imap)
(nnmail-expiry-target
"nnimap+gmail:[Gmail]/Trash")
(nnmail-expiry-wait immediate))))
;; Reply to mails with matching email address
(setq gnus-posting-styles
'((".*"
(address "Bryan Frimin <bryan@frimin.fr>")
(signature
"Bryan Frimin\nhttps://www.frimin.fr\nbryan@frimin.fr")
("X-Message-SMTP-Method"
"smtp smtp.frimin.fr 587 bryan@frimin.fr"))
("gmail"
(address "Bryan Frimin <friminb@gmail.com>")
("X-Message-SMTP-Method"
"smtp smtp.gmail.com 587 friminb@gmail.com"))))
(setq gnus-message-archive-group
'(("frimin" "nnimap+frimin:Sent")
("gmail" "[Gmail]/Sent Mail")
(".*" "nnimap+frimin:Sent")))
(setq gnus-gcc-mark-as-read t)
Configure SMTP server.
(setq smtpmail-default-smtp-server "smtp.frimin.fr")
(setq smtpmail-smtp-server "smtp.frimin.fr")
(setq smtpmail-stream-type 'starttls)
(setq smtpmail-smtp-service 587)
(setq smtpmail-retries 7)
(setq smtpmail-queue-mail nil)
(setq send-mail-function 'smtpmail-send-it)
(setq message-send-mail-function 'smtpmail-send-it)
Contact
(use-package bbdb
:ensure t
:straight t
:init
(bbdb-initialize 'gnus)
(bbdb-initialize 'message)
:config
(setq bbdb-offer-save 1) ; save without asking
(setq bbdb-use-pop-up t) ; allow popups for addresses
(setq bbdb-electric-p t) ; be disposable with SPC
(setq bbdb-popup-target-lines 1) ; very small popup
(setq bbdb-dwim-net-address-allow-redundancy t) ; always use full name
(setq bbdb-quiet-about-name-mismatches 2) ; shiw name-mismacthes 2 secs
(setq bbdb-always-add-address t)
(setq bbdb-file "~/.bbdb"))
Misc
Make GNUS not check for any new newsgroups and stops gnus from trying to filter out outdated newsgroups.
(setq gnus-check-new-newsgroups nil)
(setq gnus-check-bogus-newsgroups nil)
Kill mail buffer after sending an email.
(setq message-kill-buffer-on-exit t)
Don’t deal with HTML news.
(setq mm-discouraged-alternatives '("text/html" "text/richtext"))
(setq mm-text-html-renderer 'w3m)
(setq gnus-blocked-images "ads")
Org
(use-package org
:straight t
:ensure org-plus-contrib
:config
(setq org-hide-emphasis-markers t)
(setq org-startup-folded t)
(setq org-startup-indented t)
(setq org-startup-with-inline-images t)
(setq org-ellipsis " ▼")
(setq org-todo-keywords
'((sequence "TODO" "WORK" "STOP" "VERIFY" "|" "DONE" "DELEGATED")))
(setq org-todo-keyword-faces
'(("TODO" . org-warning)
("WORK" . "yellow")
("STOP" . "red")
("VERIFY" . "orange")
("DONE" . "green")
("DELEGATED" . "blue"))))
Use unicode bullet instead of asterix.
(use-package org-superstar
:straight t
:config
(add-hook 'org-mode-hook (lambda () (org-superstar-mode 1)))
:custom
(org-superstar-headline-bullets-list '("◉" "○" "●" "○" "●" "○" "●")))
Customize org appearance.
(require 'color)
(set-face-attribute 'org-block nil
:background (color-darken-name
(face-attribute 'default :background) 3))
(set-face-attribute 'org-block-begin-line nil
:background (color-darken-name
(face-attribute 'default :background) 3)
:foreground "#4d4d4d")
(set-face-underline 'org-ellipsis nil)
Languages
Understand camelCaseWords
as many words instead of one long word.
(add-hook 'prog-mode-hook 'subword-mode)
See column for syntax with identation.
(use-package highlight-indent-guides
:straight t
:config
(setq highlight-indent-guides-method 'column)
:hook
((yaml-mode-hook . highlight-indent-guides-mode)))
Autocomplete
Emacs is not compatible by default with LSP.
(use-package lsp-mode
:straight t
:commands
(lsp lsp-deferred)
:init
(setq lsp-prefer-flymake nil) ;; use flycheck not flymake
(setq lsp-log-io t)
(setq lsp-keymap-prefix "C-c l")
(setq lsp-headerline-breadcrumb-enable nil))
Install flycheck as lsp mode need it.
(use-package flycheck
:straight t
:init (global-flycheck-mode))
Use company as auto complete package.
(use-package company
:straight t
:after lsp-mode
:hook
(lsp-mode . company-mode)
:bind
(:map company-active-map
("<tab>" . company-complete-selection))
(:map lsp-mode-map
("<tab>" . company-indent-or-complete-common))
:custom
(company-minimum-prefix-length 1)
(company-idle-delay 0.0))
LSP mode use yasnippet.
(use-package yasnippet
:straight t
:hook
(after-init-hook . yas-global-mode))
Configure lsp ui mode
(use-package lsp-ui
:straight t
:commands lsp-ui-mode
:config
(setq lsp-ui-sideline-show-diagnostics t)
(setq lsp-ui-sideline-show-hover t)
(setq lsp-ui-sideline-update-mode t)
(setq lsp-ui-doc-enable t))
Snippet
(use-package yasnippet
:straight t
:config
(add-to-list 'yas-snippet-dirs "~/.emacs.d/snippets")
(yas-reload-all)
(yas-global-mode))
Comment
Basic configuration for the newcomment
mode.
- Replace
M-;
byC-;
- Remove comment with
C-:
- Ident comment with
M-;
(defun gearnode/comment (&optional arg)
(interactive "*P")
(if (use-region-p)
(comment-dwim arg)
(save-excursion
(comment-line arg))))
(use-package newcomment
:straight nil
:config
(setq comment-multi-line t)
(setq comment-style 'multi-line)
(setq comment-fill-column nil)
(setq comment-empty-lines t)
:bind
(("C-;" . gearnode/comment)
("C-:" . comment-kill)
("M-;" . comment-indent)))
Ruby
Enable ruby-mode
in various files that are not obvious Ruby files.
(defun gearnode/ruby-hook ()
(setq-local fill-column 90))
(use-package ruby-mode
:hook
(ruby-mode-hook . gearnode/ruby-hook)
:mode
(("Gemfile" . ruby-mode)
("Rakefile" . ruby-mode)
("\\.rake$" . ruby-mode)
("\\.rb$" . ruby-mode)
("\\.ru$" . ruby-mode)
("\\.gemspec$" . ruby-mode)
("\\.irbrc$" . ruby-mode)))
Erlang
(defun gearnode/erlang-hook ()
(setq-local fill-column 78))
(use-package erlang
:straight t
:config
(setq erlang-electric-commands '())
(setq erlang-man-download-url
"https://erlang.org/download/otp_doc_man_24.0.tar.gz")
(setq erlang-indent-level 2)
:hook
(erlang-mode-hook . display-fill-column-indicator-mode)
(erlang-mode-hook . gearnode/erlang-hook)
(erlang-mode-hook . lsp-deferred)
:mode
(("\\.erl$" . erlang-mode)
("\\.hrl%" . erlang-mode)
("\\.app\\.src$" . erlang-mode)
("rebar\\.config" . erlang-mode)
("rebar\\.lock" . erlang-mode)))
Reconize escript
shebang.
(add-to-list 'interpreter-mode-alist
'("escript" . erlang-mode))
NGINX
(use-package nginx-mode
:straight t)
PHP
(use-package php-mode
:straight t
:ensure t)
Docker
Support syntax highlighting for Dockerfile file.
(use-package dockerfile-mode
:straight t
:mode
(("Dockerfile" . dockerfile-mode)
("Dockerfile\\.*" . dockerfile-mode)
("\\.dockerfile$" . dockerfile-mode)))
Markdown
Markdown rich editing support.
(use-package markdown-mode
:straight t
:config
(setq markdown-fontify-code-blocks-natively t)
:mode
("\\.md$"))
Enable editing of code block in indirect buffers using `C-c ‘`
(use-package edit-indirect
:straight t
:after markdown-mode)
JSONNET
Support syntax highlighting for JSONNET file.
(use-package jsonnet-mode
:straight t)
YAML
Support syntax highlighting for YAML files.
(use-package yaml-mode
:straight t
:mode
(("\\.yaml$" . yaml-mode)
("\\.yml$" . yaml-mode)))
Shell scripts
Enable sh-mode
in various files that are not obvious shell scripts.
(use-package sh-script
:mode
(("PKGBUILD" . sh-mode)
("Stackfile" . sh-mode)))
Terraform
(use-package terraform-mode
:straight t
:config
(setq terraform-indent-level 4))
Go
(use-package go-mode
:straight t
:hook
(go-mode-hook . lsp-deferred)
(before-save-hook . gofmt-before-save))
Javascript
(setq js-indent-level 2)
Typescript
(use-package typescript-mode
:straight t
:config
(setq-default typescript-indent-level 2))
Rust
(use-package rust-mode
:straight t
:config
(setq rust-format-on-save t)
:hook
(rust-mode-hook . lsp-deferred))
x509 certificates
(use-package x509-mode
:straight t
:ensure t)
Search
(use-package rg
:straight t
:config
(rg-enable-default-bindings))
Dired
(require 'dired)
Kill buffers of files/directories that are deleted in dired.
(setq dired-clean-up-buffers-too t)
Always copy directories recursively instead of asking every time.
(setq dired-recursive-copies 'always)
Ask before recursively deleting a directory.
(setq dired-recursive-deletes 'top)
Dired listing switches:
-a
: Do not ignore entries starting with.-l
: Use long listing format.-G
: Do not print group names likeusers
.-h
: Human-readable sizes like 1K, 234M, etc.-v
: Do natural sort..
so the file names starting with.
will show up first.-F
: Classify filenames by appending*
to executables,/
to directories, etc.
(setq dired-listing-switches "-alGhvF --group-directories-first")
Project management
Basic projectile configuration.
(use-package projectile
:straight t
:init
(projectile-mode +1)
:config
(setq projectile-project-search-path '("~/Workspace"))
(setq projectile-indexing-method 'alien)
(setq projectile-sort-order 'access-time)
(setq projectile-enable-caching t)
(setq projectile-file-exists-remote-cache-expire (* 10 60))
:bind
(:map projectile-mode-map
("s-p" . projectile-command-map)
("C-c p" . projectile-command-map)))
Incremental completions
(use-package helm
:straight t
:ensure t
:init
(helm-mode 1)
:config
(setq helm-always-two-window nil)
(setq helm-default-display-buffer-functions '(display-buffer-in-side-window))
(setq helm-display-buffer-default-height 16)
(setq helm-buffer-max-length 30)
(setq helm-boring-buffer-regexp-list
(list
"\\*Customize"
"erlang-ls"
"magit"
"lsp"
"\\*org-src"
"\\*code-conversion-work\\*"
"straight"
"\\*Echo Area"
"\\*Minibuf"
"\\*Shell Command Output\\*"
"\\*helm"
"\\*godoc "))
:bind
(("M-x" . helm-M-x)
("C-x C-b" . helm-buffers-list)
("C-x C-y" . helm-show-kill-ring)
("C-x C-f" . helm-find-files)))
RFC
(use-package rfc-mode
:straight t
:config
(setq rfc-mode-directory (expand-file-name "~/rfc/"))
:bind
("C-c r" . rfc-mode-browse))
TO REFACTOR
(use-package emacs
:config
(setq frame-title-format '("%b"))
(setq echo-keystrokes 0.25)
(setq default-input-method "greek"))