Enabling lexical binding improves performance.
;;; init.el --- -*- lexical-binding: t -*-
First of all, we load the private config that you have to set yourself, in your own private.el. You have to set up the user mail address and elfeed feeds.
(load "~/.emacs.d/private.el")
We disable the garbage collector at launch time to improve performances.
(setq gc-cons-threshold most-positive-fixnum
gc-cons-percentage 0.6)
After startup, we set it back to a 16MB threshold.
(add-hook 'emacs-startup-hook
(lambda ()
(setq gc-cons-threshold 16777216
gc-cons-percentage 0.1)))
We add the melpa package archive which contains most of emacs packages.
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
(setenv "PATH" (concat (getenv "PATH") (concat (concat ":" (getenv "HOME")) "/go/bin")))
The use-package package provides an easier way to configure and install package, we load it since it’s already installed as a git submodule.
(add-to-list 'load-path "~/.emacs.d/use-package")
(require 'use-package)
Then we tell use-package
to check if a package is installed and install it if
it’s not unless we told it not to.
(require 'use-package-ensure)
(setq use-package-always-ensure t)
The use-package-ensure-system-package provides a use-package
extension to
check and install system dependencies.
(use-package use-package-ensure-system-package)
The auto-package-update package provides automatic updates with
use-package
. We tell it to only update packages after 5 seconds in idle.
(use-package auto-package-update
:defer 5
:config
(setq auto-package-update-delete-old-versions t)
(setq auto-package-update-hide-results t)
(auto-package-update-maybe))
First, make emacs verify all TLS connections.
(setq tls-checktrust t
gnutls-verify-error t)
Then, we give emacs the location of certificates.
(let ((trustfile "/etc/ssl/certs/ca-certificates.crt"))
(setq tls-program
`(,(format "gnutls-cli --x509cafile %s -p %%p %%h" trustfile)
,(format "openssl s_client -connect %%h:%%p -CAfile %s -no_ssl2 -ign_eof"
trustfile)))
(setq gnutls-trustfiles (list trustfile)))
Switch to utf-8 encoding.
(set-default-coding-systems 'utf-8)
Use y/n prompts instead of yes/no ones.
(fset 'yes-or-no-p 'y-or-n-p)
Install doom themes, enable italic and bold fonts and enable the nord theme. And enable org-mode’s fontification.
(use-package doom-themes
:config
(setq doom-themes-enable-bold t
doom-themes-enable-italic t)
(load-theme 'doom-nord t)
(doom-themes-visual-bell-config)
(doom-themes-org-config))
The mood-line package provides a doom-modeline inspired bar, based on the original emacs bar. We also add time in the bar.
(use-package mood-line
:config
(mood-line-mode)
(display-time-mode))
The ‘⚑’ character, used for issues by the bar, doesn’t work well with the font I use. So we use the el-patch package which allows to patch the bar.
(use-package el-patch)
(el-patch-feature mood-line)
(with-eval-after-load 'mood-line
(el-patch-defun mood-line--update-flycheck-segment (&optional status)
"Update `mood-line--flycheck-text' against the reported flycheck STATUS."
(setq mood-line--flycheck-text
(pcase status
('finished (if flycheck-current-errors
(let-alist (flycheck-count-errors flycheck-current-errors)
(let ((sum (+ (or .error 0) (or .warning 0))))
(propertize (concat
(el-patch-swap "⚑ Issues: " "Issues: ")
(number-to-string sum)
" ")
'face (if .error
'mood-line-status-error
'mood-line-status-warning))))
(propertize "✔ Good " 'face 'mood-line-status-success)))
('running (propertize "Δ Checking " 'face 'mood-line-status-info))
('errored (propertize "✖ Error " 'face 'mood-line-status-error))
('interrupted (propertize "⏸ Paused " 'face 'mood-line-status-neutral))
('no-checker "")))))
We use the emacs-dashboard package which displays a nice home page with recent files, agenda items and projects.
(use-package dashboard
:custom
(dashboard-show-shortcuts nil)
(dashboard-items '((recents . 20)
(agenda . 5)
(projects . 8)))
:config
(global-page-break-lines-mode)
(dashboard-setup-startup-hook))
To get dashboard when using emacsclient -c
, we need the following line:
(setq initial-buffer-choice (lambda () (get-buffer "*dashboard*")))
I like the scientifica font, you can use another font format, however I’ve had problems with this font in other formats.
(set-frame-font
"-HBnP-scientifica-normal-normal-normal-*-11-*-*-*-*-0-iso10646-1")
However, this won’t work with emacsclient -c
so we need this:
(add-to-list 'default-frame-alist
'(font . "-HBnP-scientifica-normal-normal-normal-*-11-*-*-*-*-0-iso10646-1"))
By default variable-pitch
uses a different font.
(custom-set-faces
'(variable-pitch ((t nil)))
'(fixed-pitch ((t nil))))
We disable unuseful UI elements.
(menu-bar-mode -1)
(scroll-bar-mode -1)
(tool-bar-mode -1)
Enable line numbers in programming modes and org-mode.
(add-hook 'prog-mode-hook 'display-line-numbers-mode)
(add-hook 'org-mode-hook 'display-line-numbers-mode)
The ivy package provides a completion engine. We set a higher minibuffer than default.
(use-package ivy
:config
(ivy-mode 1)
:custom
(ivy-height 20))
The swiper package provides an isearch alternative using ivy.
(use-package swiper
:commands (swiper))
The counsel package provides alternative commands for emacs builtin ones which uses ivy.
(use-package counsel
:after (ivy)
:defer t
:config
(counsel-mode 1)
(setq ivy-initial-inputs-alist nil))
We use the prescient completion backend. We activate the persist option which allows history between different emacs sessions.
(use-package prescient
:after (ivy)
:config (prescient-persist-mode 1))
We install the ivy backend of prescient.
(use-package ivy-prescient
:after (ivy prescient)
:config (ivy-prescient-mode 1))
We use the projectile package to get good project completion and tooling.
(use-package projectile
:commands (project-find-file)
:custom
(projectile-completion-system 'ivy))
We use electric pair mode to get the corresponding delimiters when we type one. For instance ‘(’ will also add a ‘)’.
(electric-pair-mode 1)
We use the rainbow-delimiters package to get matching parentheses and brackets of same colour.
(use-package rainbow-delimiters
:defer t
:hook (prog-mode . rainbow-delimiters-mode))
Set up the tabulation width and the default style in c.
(setq tab-width 8
electric-indent-inhibit t
c-default-style "bsd"
c-basic-offset tab-width)
Make backspace delete a full tab instead of a space at a time.
(setq backward-delete-char-untabify-method 'hungry)
Only use tabs in c mode, and use spaces in other programming languages.
(add-hook 'emacs-lisp-mode-hook '(lambda () (setq indent-tabs-mode nil)))
(add-hook 'tuareg-mode-hook '(lambda () (setq indent-tabs-mode nil)))
(add-hook 'org-mode-hook '(lambda () (setq indent-tabs-mode nil)))
(add-hook 'c-mode-hook '(lambda () (setq indent-tabs-mode t)))
The smart tabs package allows us to use tabs for code blocks and spaces to align things like tables and arguments, so we enable it in c mode.
(use-package smart-tabs-mode
:config
(smart-tabs-insinuate 'c))
The flycheck package provides on the fly syntax cheking. We enable it in all buffers. The hook makes flycheck stop complaining about package presentation when checking a emacs-lisp block from org-mode. We also change the way error are represented, replacing the wave by a straight underline.
(use-package flycheck
:custom-face
(flycheck-info ((t (:underline "#A3BE8C"))))
(flycheck-error ((t (:underline "#BF616A"))))
(flycheck-warning ((t (:underline "#EBCB8B"))))
:init (global-flycheck-mode)
:hook
(org-src-mode . (lambda ()
(setq-local flycheck-disabled-checkers
'(emacs-lisp-checkdoc)))))
Replace flycheck’s default fringe with a bitmap arrow.
(define-fringe-bitmap 'flycheck-error-bmp
(vector #b10000000
#b11000000
#b11100000
#b11110000
#b11100000
#b11000000
#b10000000)
nil nil 'center)
(flycheck-redefine-standard-error-levels nil 'flycheck-error-bmp)
The company package provides in buffer auto-completion. We tell it to start completing from the first character and provide keybindings to move in suggestions without moving from the home row. We activate it in programming modes and in org-mode.
(use-package company
:hook
((prog-mode org-mode) . company-mode)
:bind
(:map company-active-map
("<tab>" . 'company-complete-selection)
("M-l" . 'company-complete-common)
("M-j" . 'company-select-next)
("M-k" . 'company-select-previous))
:custom
(company-idle-delay 0.1)
(company-minimum-prefix-length 1))
We use the prescient integration with company to get better sorted auto-completion.
(use-package company-prescient
:after (company prescient)
:config (company-prescient-mode))
The irony-mode package provides auto-completion and syntax checking for C/C++
based on libclang. So it needs to be installed using irony-install-server
. Of
course we only enable it in c mode.
(use-package irony
:hook
(c-mode . irony-mode)
(irony-mode . irony-cdb-autosetup-compile-options))
To get syntax checking with irony we use the flycheck-irony backend of flycheck which we load after flycheck and irony and enable it when flycheck is enabled.
(use-package flycheck-irony
:after (flycheck irony)
:hook (flycheck-mode . flycheck-irony-setup))
To get auto-completion with irony we use the company-irony backend of company.
(use-package company-irony
:after (irony company)
:config
(add-to-list 'company-backends 'company-irony))
We also use the company-irony-c-headers of company to get completion of headers file.
(use-package company-irony-c-headers
:after (irony company)
:config (add-to-list 'company-backends 'company-irony-c-headers))
We can get documentation from c files using the irony backend of eldoc.
(use-package irony-eldoc
:after (irony)
:hook (irony-mode . irony-eldoc))
We define a function to use uncrustify on the local buffer.
(defun uncrustify ()
"Use uncrustify on the current buffer."
(interactive)
(let ((save-point (point)))
(shell-command-on-region
(point-min)
(point-max)
"uncrustify -c ~/.uncrustify.cfg"
(current-buffer)
t
"*uncrustify error buffer"
nil)
(goto-char save-point)))
We add summon this function when saving a c file.
(defun uncrustify-on-save ()
"Unable uncrustify on save on the local buffer"
(interactive)
(add-hook 'before-save-hook 'uncrustify nil t))
;(add-hook 'c-mode-hook 'uncrustify-on-save)
The cmake-font-lock package provides advanced syntax highlighting for CMake files.
(use-package cmake-font-lock
:mode ("\\.cmake\\'||CMakeLists.txt"))
The tuareg package provides a REPL, syntax highlighting and a debugger. We tell it to align patterns in pattern matching.
(use-package tuareg
:custom
(tuareg-match-patterns-aligned t)
:mode ("\\.ml\\'" . tuareg-mode))
The merlin package provides auto-completion, syntax-checking and type annotations for ocaml. We use with tuareg and add it to the list of company backends, so we load it after these packages.
(use-package merlin
:after (tuareg company)
:config
(add-to-list 'company-backends 'merlin-company-backend)
:hook
((caml-mode tuareg-mode) . merlin-mode))
We can get documentation from ocaml files using the merlin backend of eldoc.
(use-package merlin-eldoc
:hook ((tuareg-mode caml-mode) . merlin-eldoc-setup)
:custom
(eldoc-echo-area-use-multiline-p t)
(merlin-eldoc-max-lines 6))
By default merlin uses flymake, however we use flycheck, so we disable its internal error reporting mechanism and replace it by a one which uses flycheck.
(use-package flycheck-ocaml
:after (merlin flycheck)
:config
(setq merlin-error-after-save nil)
(flycheck-ocaml-setup))
The SLIME package provides Common Lisp IDE features.
The slime-company package a company backend for the SLIME package.
; (use-package sly)
Unable auto fill in org mode to make paragraphs of 80 lines automaticlly. We
only load the emacs-lisp
backend of literate programming with org-mode.
(use-package org
:defer t
:custom
(fill-column 80)
:hook
(org-mode . auto-fill-mode)
:config
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t))))
The toc-org auto generates table of contents on the first outline with a :TOC:
tag, so we turn it in org files and load it after org-mode.
(use-package toc-org
:after (org)
:hook (org-mode . toc-org-enable))
The magit package provides a wrapper upon most of often used git commands.
(use-package magit
:commands (magit-commit magit-push magit-status magit-pull))
The git-gutter and git-gutter-fringe packages provide a nice visual indicator in the fringe to see which lines are modified, added or deleted and not commited yet.
(use-package git-gutter
:hook ((prog-mode org-mode) . git-gutter-mode))
(use-package git-gutter-fringe)
Provides a nice bitmap fringe for git-gutter.
(setq-default fringes-outside-margins t)
(define-fringe-bitmap 'git-gutter-fr:added
(vector #b11100000)
nil nil '(center repeated))
(define-fringe-bitmap 'git-gutter-fr:modified
(vector #b11100000)
nil nil '(center repeated))
(define-fringe-bitmap 'git-gutter-fr:deleted
(vector #b10000000
#b11000000
#b11100000
#b11110000)
nil nil 'bottom)
Elfeed is a feed reader supporting Atom and RSS feeds. Feeds are set in the
private.el
file in a list named elfeed-feeds
. We only load the package when
the elfeed
command is called, and update feeds every time we open it. We also
tell that elfeed needs curl
.
(use-package elfeed
:ensure-system-package (curl)
:config (elfeed-update)
:commands (elfeed))
First of all, we create a function to update the mail box, by downloading and
indexing new emails using notmuch
and offlineimap
. We also tag each email
sent by the user with a special tag.
(defun update-mail ()
"Update offlineimap and notmuch."
(interactive)
(start-process-shell-command
"offlineimap"
"offlineimap"
"offlineimap -o && notmuch new")
(start-process-shell-command
"notmuch"
"notmuch"
(concat "notmuch tag +sent -- from:" user-mail-address)))
Notmuch is an email-client. We only load the package when the notmuch
command
is called. You need to install the notmuch
and notmuch-emacs
packages with
your package manager. We tell use-package
not to install notmuch
since it’s
already installed by the package manager. We also tell emacs which commands to
use to send email - the smtp server has to be configured in private.el
. We
tell that notmuch
needs gnutls-cli
and notmuch
.
(use-package notmuch
;; :custom-face
;; (widget-field
;; ((t
;; (:box
;; (:line-width
;; (1 . 1)
;; :color nil :style none)
;; :foreground "#ECEFF4" :background "#242832"))))
:config (update-mail)
:ensure nil
:commands (notmuch notmuch-mua-new-mail)
:ensure-system-package
((gnutls-cli . gnutls-bin)
notmuch offlineimap)
:custom
(notmuch-show-logo nil)
(message-send-mail-function 'smtpmail-send-it)
(mail-send-mail-function 'smtpmail-send-it)
(message-auto-save-directory "~/.mail/draft")
(message-kill-buffer-on-exit t)
(message-directory "~/.mail"))
We set eww
as the default web browser to use. We also customize a bit the look
so it looks more coherent with the rest of the configuration.
(use-package eww
:ensure nil
:commands (eww)
:custom-face
(eww-form-submit ((t (:inherit custom-button))))
(eww-valid-certificate ((t (:weight bold :foreground "#A3BE8C"))))
(eww-form-text
((t
(:box
(:line-width
(1 . 1)
:color nil :style none)
:foreground "#ECEFF4" :background "#242832"))))
:custom (browse-url-browser-function 'eww-browse-url))
The Evil package provides emulation for the main features of Vim.
(use-package evil
:init
(setq evil-want-keybinding nil)
:config
(evil-mode 1))
The Evil Collection package provides Vim emulation for packages not covered by Evil. We already modified company keybindings so we disable evil’ one.
(use-package evil-collection
:after (evil)
:custom (evil-collection-company-use-tng nil)
:config
(evil-collection-init))
The undo-tree package provides a more traditional undo system without loosing information about past states of the buffer. Enable persistent buffer undo.
(use-package undo-tree
:custom
(undo-tree-auto-save-history t)
(undo-limit 10000)
:after (evil)
:config
(global-undo-tree-mode))
The avy package provides a way to move in the buffer using a char-based decision tree.
(use-package avy)
The anzu package provides search information for various modes in the mode line.
(use-package anzu
:config (global-anzu-mode)
:custom-face
(anzu-mode-line ((t (:foreground "#EBCB8B")))))
The general package provides an easy way to bind keys and integrates well with evil.
(use-package general
:after (evil))
We define some keybindings for often used commands. They all start with the
prefix space, à la spacemacs. We need to use the keymap override
otherwise
evil would bind the space key.
(general-define-key
:prefix "SPC"
:states 'normal
:keymaps 'override
"SPC" 'projectile-find-file
"sb" 'swiper
"ff" 'find-file
"bb" 'counsel-switch-buffer
"fr" 'counsel-recentf
"kl" 'counsel-flycheck
"cr" 'comment-region
"cc" 'comment-line
"gc" 'magit-commit
"gp" 'magit-push
"gs" 'magit-status
"al" 'avy-goto-line
"ac" 'avy-goto-char-2
"aw" 'avy-goto-word-1
"at" 'avy-goto-char-timer
"ml" 'notmuch
"mk" 'notmuch-mua-new-mail
"mf" 'elfeed
"p" 'projectile-command-map)
We add some key bindings to edit source blocks in org-mode
.
(general-define-key
:prefix "SPC"
:states 'normal
:keymaps '(org-mode-map)
"cf" 'org-edit-special)
(general-define-key
:prefix "SPC"
:states 'normal
:keymaps '(org-src-mode-map)
"cf" 'org-edit-src-exit)
Then we add keybindings for message-mode
.
(general-define-key
:prefix "SPC"
:states 'normal
:keymaps '(message-mode-map notmuch-message-mode-map)
"ms" 'message-send-and-exit)
Finally, we add some keys for full sized keyboards.
(general-define-key
"<next>" '(lambda ()
(interactive)
(next-line 40))
"<prior>" '(lambda ()
(interactive)
(previous-line 40)))