From 2a12410cdce2fcea09b2acf06458a418fb9899c1 Mon Sep 17 00:00:00 2001 From: Miquel Sabaté Solà Date: Thu, 15 Feb 2018 09:13:23 +0100 Subject: emacs: ignore init.html file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miquel Sabaté Solà --- emacs/init.html | 3010 ------------------------------------------------------- 1 file changed, 3010 deletions(-) delete mode 100644 emacs/init.html (limited to 'emacs') diff --git a/emacs/init.html b/emacs/init.html deleted file mode 100644 index fd9380b..0000000 --- a/emacs/init.html +++ /dev/null @@ -1,3010 +0,0 @@ - - - - -mssola's GNU Emacs configuration - - - - - - - - - - -
-

mssola's GNU Emacs configuration

- - -
-

Preface

-
-

-This is my attempt of getting my configuration organized with literate -programming and org-babel. I took the workflow I'm following from @larstvei. -The idea is that the init.el file will replace itself on the first execution -with the tangled version of this file. This first version will also be -byte-compiled. This means that all changes are to be made on the init.org -file always. The initial contents of the init.el are: -

- -
- -
;; We can't tangle without org!
-(require 'org)
-
-;; Follow symlinks
-(setq vc-follow-symlinks t)
-
-;; Open the configuration
-(find-file (concat user-emacs-directory "init.org"))
-
-;; Tangle it
-(org-babel-tangle)
-
-;; Load it
-(load-file (concat user-emacs-directory "init.el"))
-
-;; Finally byte-compile it
-(byte-compile-file (concat user-emacs-directory "init.el"))
-
-
- -

-There is no reason to track the init.el file, and no reason to change this -file. In order to ensure this, make sure to apply the following command after -cloning: -

- -
- -
git update-index --assume-unchanged emacs/init.el
-
-
- -

-Moreover, in order to avoid manually tangling and compiling the init.org file -on each change, the following function is provided: -

- -
- -
(defun tangle-init ()
-  "If the current buffer is 'init.org' the code-blocks are
-  tangled, and the tangled file is compiled. Morever, an init.html is generated."
-
-  (when (or (equal (buffer-file-name)
-                   (expand-file-name (concat user-emacs-directory "init.org")))
-            (string-suffix-p "dotfiles/emacs/init.org" (buffer-file-name)))
-
-    ;; Avoid running hooks when tangling
-    (let ((prog-mode-hook nil))
-      (org-babel-tangle)
-      (org-html-export-to-html)
-      (byte-compile-file (concat user-emacs-directory "init.el")))))
-
-(add-hook 'after-save-hook 'tangle-init)
-
-
-
-
- -
-

Introduction

-
-

-I'm using GNU Emacs 25, but everything should be working in GNU Emacs 24. There -are some exceptions to this (e.g. webkit support), but these cases are -individually handled. -

- -
- -
(unless (>= emacs-major-version 24)
-  (error "Don't be a cheap bastard and upgrade to at least GNU Emacs 24"))
-
-
- -

-Temporarily reduce garbage collection so startup time is lower. Idea taken from -@purcell. -

- -
- -
(defconst mssola-initial-gc-cons-threshold gc-cons-threshold
-  "Initial value of `gc-cons-threshold' at start-up time.")
-(setq gc-cons-threshold (* 1024 1024 1024))
-(add-hook 'after-init-hook
-          (lambda () (setq gc-cons-threshold mssola-initial-gc-cons-threshold)))
-
-
- -

-User name and email. -

- -
- -
(setq user-full-name "Miquel Sabaté Solà"
-      user-mail-address "mikisabate@gmail.com")
-
-
-
-
- -
-

General

-
-
-

GUI

-
-

-I like a minimalistic GUI. Because of this, almost all GUI elements have been -disabled or tweaked in some custom way. -

- -

-The frame title is "<login>: <path>". If we are not editing a file, then the -name of the buffer is displayed (e.g. "mssola: scratch"). -

- -
- -
(setq frame-title-format
-  '((:eval
-    (concat (user-real-login-name) ": "
-      (if (buffer-file-name)
-        (abbreviate-file-name (buffer-file-name))
-        "%b")))))
-
-
- -

-Disable the menu, scroll and tool bars. At the same time, enable line and column -modes. -

- -
- -
(menu-bar-mode -1)
-(when (fboundp 'set-scroll-bar-mode)
-  (set-scroll-bar-mode nil))
-(when (fboundp 'tool-bar-mode)
-  (tool-bar-mode -1))
-(when (fboundp 'tooltip-mode)
-  (tooltip-mode 0))
-
-(line-number-mode 1)
-(column-number-mode 1)
-
-;; Nice scrolling
-(setq scroll-margin 0
-      scroll-conservatively 100000
-      scroll-preserve-screen-position 1)
-
-
-
-
- -
-

Basic editing configuration

-
-

-Use UTF-8 always. -

- -
- -
(prefer-coding-system 'utf-8)
-(set-default-coding-systems 'utf-8)
-(set-terminal-coding-system 'utf-8)
-(set-keyboard-coding-system 'utf-8)
-(set-language-environment 'utf-8)
-
-
- -

-Some editing tweaks like tabs vs spaces, maximum column width, etc. -

- -
- -
;; Emacs modes typically provide a standard means to change the indentation
-;; width (e.g. c-basic-offset). Moreover, even though I prefer tabs over space,
-;; for most coding conventions this is not the case (e.g. ruby). For this
-;; reason, I will disable them by default and enabled them back for each
-;; specific case (e.g. C). I'm also using the smart-tabs-mode package, see
-;; below in the languages section.
-(setq-default indent-tabs-mode nil)
-(setq-default tab-width 4)
-
-;; Maximum 80 columns.
-(setq-default fill-column 80)
-(setq-default auto-fill-function 'do-auto-fill)
-
-;; Do not break lines
-(set-default 'truncate-lines t)
-
-;; Delete the selection with a keypress.
-(delete-selection-mode t)
-
-;; Remove whitespaces at the end of line
-(add-hook 'before-save-hook 'delete-trailing-whitespace)
-
-;; Cursor
-(blink-cursor-mode 0)
-(global-hl-line-mode -1)
-(show-paren-mode 1)
-
-
-
-
- -
-

Font and theme

-
-

-I'm using "Droid Sans Mono" simply because I've grown used to it. -

- -
- -
(set-frame-font "Droid Sans Mono Dotted for Powerline-10")
-(add-to-list 'default-frame-alist '(font . "Droid Sans Mono Dotted for Powerline-10"))
-
-; Emacs in daemon mode does not like `set-face-attribute` because this is only
-; applied if there is a frame in place, which doesn't happen when starting the
-; daemon. Thus, we should call that after the frame has been created (e.g. by
-; emacsclient).
-; See: https://lists.gnu.org/archive/html/help-gnu-emacs/2015-03/msg00016.html
-(add-hook 'after-make-frame-functions-hook
-  (lambda ()
-    (set-face-attribute 'default t :font "Droid Sans Mono Dotted for Powerline-10")))
-
-
- -

-I've hacked my own theme called soria. This theme combines the vim theme -xoria256 with the openSUSE branding guidelines. -

- -
- -
(load-theme 'soria t)
-
-
- -

-When hacking your own theme, sometimes you want to know what face is the one -that you see on the screen right now. This function from @thblt allows me to -get exactly that: -

- -
- -
(defun mssola-face-at-point (pos)
-  "Writes a message with the name of the face at the current point.  The POS
-  argument contains the current position of the cursor."
-
-  (interactive "d")
-
-  (let ((face (or (get-char-property (point) 'read-face-name)
-                  (get-char-property (point) 'face))))
-    (if face (message "Face: %s" face) (message "No face at %d" pos))))
-
-(global-set-key (kbd "C-c f") 'mssola-face-at-point)
-
-
-
-
- -
-

General global key bindings

-
-

-Use kill-this-buffer instead of kill-buffer. -

- -
- -
(global-set-key (kbd "C-x k") 'kill-this-buffer)
-
-
- -

-Disable C-z. It will later on be picked up by Evil's config as the escape -sequence. This is here to make sure that it will be disabled even if Evil -cannot be loaded due to some error. -

- -
- -
(global-unset-key (kbd "C-z"))
-
-
- -

-Disable all the Fn keys. -

- -
- -
(dotimes (i 12)
-  (global-unset-key (kbd (format "<f%d>" (+ i 1)))))
-
-
- -

-Disable overwrite-mode. -

- -
- -
(define-key global-map [(insert)] nil)
-
-
-
-
- -
-

Others

-
-

-Revert buffers automatically when underlying files are changed externally. -

- -
- -
(global-auto-revert-mode t)
-
-
- -

-Follow symlinks. -

- -
- -
(setq vc-follow-symlinks t)
-
-
- -

-Remove the initial message from the scratch buffer. -

- -
- -
(setq initial-scratch-message nil)
-
-
- -

-Never kill the scratch buffer, bury it instead. -

- -
- -
(defadvice kill-buffer (around kill-buffer-around-advice activate)
-  (let ((buffer-to-kill (ad-get-arg 0)))
-    (if (equal buffer-to-kill "*scratch*")
-        (bury-buffer)
-      ad-do-it)))
-
-(defadvice kill-this-buffer (around kill-buffer-around-advice activate)
-  (let ((buffer-to-kill (ad-get-arg 0)))
-    (if (equal buffer-to-kill "*scratch*")
-        (bury-buffer)
-      ad-do-it)))
-
-
- -

-No backups -

- -
- -
(setq-default make-backup-files nil)
-(setq-default auto-save-default nil)
-
-
- -

-But at least save the list of recently open files. -

- -
- -
(require 'recentf)
-
-(recentf-mode 1)
-(global-set-key "\C-x\ \C-r" 'recentf-open-files)
-
-; Save the list every 5 minutes
-(run-at-time nil (* 5 60) 'recentf-save-list)
-
-
- -

-No welcome screen -

- -
- -
(setq-default inhibit-startup-message t)
-
-
- -

-Enable y/n answers -

- -
- -
(fset 'yes-or-no-p 'y-or-n-p)
-
-
- -

-Let flyspell be performant. -

- -
- -
(defvar flyspell-issue-message-flag nil)
-
-
- -

-Save custom-variables somewhere else. -

- -
- -
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
-(if (file-exists-p custom-file)
-    (load custom-file))
-
-
-
-
-
- -
-

Calendar

-
-

-We catalans start our weeks on Monday. -

- -
- -
(defvar calendar-week-start-day 1)
-
-
- -

-Global key binding. -

- -
- -
(global-set-key (kbd "M-c") 'calendar)
-
-
- -

-Fix some stuff for evil mode. -

- -
- -
(with-eval-after-load "evil"
-  (evil-set-initial-state 'calendar-mode 'normal)
-  (evil-define-key 'normal calendar-mode-map
-    "j" 'calendar-forward-week
-    "k" 'calendar-backward-week
-    "b" 'calendar-backward-day
-    "h" 'calendar-backward-day
-    "l" 'calendar-forward-day
-    "w" 'calendar-forward-day
-    "q" 'calendar-exit
-    "\C-h" 'evil-window-left
-    "\C-l" 'evil-window-right
-    "\C-j" 'evil-window-down
-    "\C-k" 'evil-window-up
-    "\C-n" 'calendar-scroll-left-three-months
-    "\C-p" 'calendar-scroll-right-three-months))
-
-
-
-
- -
-

General purpose defuns

-
-

-I want to read the latest news. That's why I define a function that downloads -the NEWS file from the git server and then opens it in a buffer. -

- -
- -
(defun mssola-view-emacs-latest-news ()
-  "Allow users to fetch the latest Emacs' NEWS file."
-  (interactive)
-
-  (url-copy-file
-   "http://git.savannah.gnu.org/cgit/emacs.git/plain/etc/NEWS"
-   "/tmp/emacs-news" t)
-
-  (find-file-read-only "/tmp/emacs-news" t))
-
-
- -

-Sometimes I want to debug my initialization time. -

- -
- -
(defun emacs-init-time ()
-  "Redefine the `emacs-init-time' function so it is more detailed.
-Idea taken from @purcell."
-
-  (interactive)
-  (let ((init-time
-         (float-time (time-subtract after-init-time before-init-time))))
-    (message "%.3fs" init-time)))
-
-
-
-
- -
-

Lisp packages

-
-
-

Custom packages

-
-

-Compile the g.el script and bind it to M-g. -

- -
- -
(byte-compile-file (concat user-emacs-directory "lisp/g.el") t)
-(global-set-key (kbd "M-g") 'g)
-
-
-
-
- -
-

use-package

-
-

-Initialize package. -

- -
- -
(require 'package)
-
-(add-to-list 'package-archives
-             '("melpa" . "http://melpa.milkbox.net/packages/") t)
-(add-to-list 'package-archives
-             '("melpa-stable" . "https://stable.melpa.org/packages/") t)
-
-(package-initialize)
-
-
- -

-I'm using use-package to handle my installed packages. I don't know if it's -the best option or what because I haven't tested all the package managers -for Emacs out there. After trying some custom functions to handle -package-install, I decided on use-package because I feel more well-organized. -

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

-Some use-package calls require diminish.el to be available. So, let's -require it here on the very top. -

- -
- -
(use-package diminish
-  :ensure t)
-
-
-
-
-
- -
-

Project

-
-

-First of all, load the silver searcher, which is a convenient and fast searcher. -Ayo silver! -

- -
- -
(use-package ag
-  :ensure t
-  :config
-
-  ; Avoid some disagreements between ag and evil.
-  (with-eval-after-load 'evil
-    (add-hook 'ag-mode-hook
-              (lambda ()
-                (define-key ag-mode-map (kbd "n") 'evil-search-next)
-                (define-key ag-mode-map (kbd "N") 'evil-search-previous)
-                (define-key ag-mode-map (kbd "gg") 'evil-goto-first-line))))
-  (setq ag-reuse-buffers t)
-  (setq ag-reuse-window t))
-
-
- -

-Then, for keeping up with my projects I use the Projectile + Helm combination. -

- -
- -
(use-package projectile
-  :ensure t
-  :config
-  (projectile-mode 1))
-
-(use-package helm
-  :ensure t
-  :config
-  (setq projectile-completion-system 'helm)
-
-  ; Allow the search pattern to be on the header. Taken from this Reddit thread:
-  ; https://www.reddit.com/r/emacs/comments/3asbyn/new_and_very_useful_helm_feature_enter_search/
-  (setq helm-echo-input-in-header-line t)
-
-  (defun helm-hide-minibuffer-maybe ()
-    "Hide the minibuffer if we are in a Helm session"
-
-    (when (with-helm-buffer helm-echo-input-in-header-line)
-      (let ((ov (make-overlay (point-min) (point-max) nil nil t)))
-        (overlay-put ov 'window (selected-window))
-        (overlay-put ov 'face (let ((bg-color (face-background 'default nil)))
-                                `(:background ,bg-color :foreground ,bg-color)))
-        (setq-local cursor-type nil))))
-
-  (add-hook 'helm-minibuffer-set-up-hook 'helm-hide-minibuffer-maybe)
-  (setq helm-split-window-inside-p t)
-
-  ; Preview files with tab
-  (define-key helm-map (kbd "<tab>") 'helm-execute-persistent-action)
-
-  ; Show available options
-  (define-key helm-map (kbd "C-a")  'helm-select-action)
-
-  ; Some vim-like bindings
-  (define-key helm-map (kbd "C-j") 'helm-next-line)
-  (define-key helm-map (kbd "C-k") 'helm-previous-line)
-
-  (global-set-key (kbd "M-x") 'helm-M-x)
-
-  (use-package helm-ag
-    :ensure t))
-
-(use-package helm-projectile
-  :ensure t
-  :config
-  (helm-projectile-on)
-
-  ; Define M-p as a way to quickly list all the available projects.
-  (with-eval-after-load 'evil
-    (define-key evil-normal-state-map (kbd "M-p")
-      'helm-projectile-switch-project)))
-
-
- -

-I use C-p as the binding for listing relevant files. This -binding works either by using helm-projectile or the regular helm-find -function. As a final touch, this binding also works for listing channels in ERC -buffers. -

- -
- -
(defun mssola-erc-helm-buffer-list ()
-  "Returns a list with the ERC buffers."
-  (mapcar 'buffer-name (erc-buffer-list)))
-
-(defconst mssola-helm-source-erc-channel-list
-      '((name . "ERC Channels")
-        (candidates . mssola-erc-helm-buffer-list)
-        (action . switch-to-buffer)))
-
-(defun mssola-erc-helm-switch-buffer ()
-  "Use helm to select an active ERC buffer."
-
-  (interactive)
-
-  (helm :sources '(mssola-helm-source-erc-channel-list)
-        :buffer "*helm-erc-channels*"))
-
-(defun mssola-find-file ()
-  "Call the proper Helm function for finding files."
-
-  (interactive)
-
-  (if (string= major-mode "erc-mode")
-      (mssola-erc-helm-switch-buffer)
-    (condition-case nil
-        (helm-projectile-find-file)
-      (error
-       (helm-find-files nil)))))
-
-(with-eval-after-load 'evil
-  (define-key evil-normal-state-map (kbd "C-p") 'mssola-find-file))
-
-
- -

-Similarly, helm-ag has two functions for applying ag on the project. I'm -binding to ,a a function that calls to the proper function. -

- -
- -
(defun mssola-helm-ag ()
-  "Call the right ag command for helm-ag."
-
-  (interactive)
-
-  (condition-case nil
-      (helm-ag-project-root)
-    (error (helm-ag))))
-
-(with-eval-after-load 'evil-leader
-  (evil-leader/set-key "a" 'mssola-helm-ag))
-
-
-
-
- -
-

Edit

-
-

-In this section I define some useful packages for editing. First of all, one of -the coolest packages out there is undo-tree. It allows you to navigate through -the undo history in a tree (because GNU Emacs is cool and keeps track of undo -actions in a tree structure instead of in a stack). This package is included in -recent versions of GNU Emacs. -

- -
- -
(with-eval-after-load 'undo-tree
-  (global-undo-tree-mode 1)
-
-  (setq undo-tree-visualizer-diff t
-        undo-tree-visualizer-timestamps t
-        undo-tree-visualizer-relative-timestamps t)
-
-  (require 'diminish)
-  (diminish 'undo-tree-mode)
-
-  (with-eval-after-load 'evil-leader
-    (evil-leader/set-key
-      "u" 'undo-tree-visualize)))
-
-
- -

-Another important package is flycheck, which is an on-the-fly syntax checking -extension. This works with lots of languages with proper glue code. -

- -
- -
(use-package let-alist
-  :ensure t)
-
-(use-package flycheck
-  :ensure t
-  :diminish
-  :config
-  (add-hook 'after-init-hook 'global-flycheck-mode)
-
-  ;; Only show the errors buffer if it isn't there and if I'm saving the
-  ;; buffer.
-  (setq flycheck-emacs-lisp-load-path 'inherit)
-  (setq flycheck-check-syntax-automatically '(mode-enabled save))
-  (setq flycheck-display-errors-function
-    #'flycheck-display-error-messages-unless-error-list))
-
-
- -

-A recurring issue in speeches and presentations is that when showing something -with your editor, you have to increase/decrease the fonts. I use the -default-text-scale package for this. -

- -
- -
(use-package default-text-scale
-  :ensure t
-  :config
-  (global-set-key (kbd "C-+") 'default-text-scale-increase)
-  (global-set-key (kbd "C--") 'default-text-scale-decrease))
-
-
- -

-Some languages use some delimiters a lot (e.g. lisp languages and -parenthesis). For this reason I'm using the rainbow-delimiters package, which -properly highlights each level in a different way (provided that your theme -supports it). -

- -
- -
(use-package rainbow-delimiters
-  :ensure t)
-
-
- -

-I never use the mouse. -

- -
- -
(use-package disable-mouse
-  :ensure t
-  :config
-  (global-disable-mouse-mode)
-  (setq global-disable-mouse-mode-lighter ""))
-
-
- -

-Sometimes you begin typing a prefix, but then you forget the following -chord. For this reason which-key was created. It will show the available -commands for the current chord as a list. -

- -
- -
(use-package which-key
-  :ensure t
-  :diminish which-key-mode
-  :config
-  (which-key-mode))
-
-
- -

-For some modes it is important to count the number of words in the text. For -this, we have wc-mode. -

- -
- -
(use-package wc-mode
-  :ensure t)
-
-
- -

-Next on the list, we have writeroom-mode. I honestly don't use this package -that often, but it's cool to have a distraction-free screen from time to time. -

- -
- -
(use-package writeroom-mode
-  :ensure t)
-
-
- -

-The expand-region package is an extension that is based on a Vim one, which -expands the region of selection with a single key chord. Even if evil covers -most of my uses, it's convenient to have this tool anyways. -

- -
- -
(use-package expand-region
-  :ensure t
-  :config
-
-  ; Set C-e as the expand command (mnemonic: expand). This command will
-  ; supercede the evil binding for "move one line", which I never use anyways.
-  (global-set-key (kbd "\C-e") 'er/expand-region)
-  (with-eval-after-load 'evil
-    (define-key evil-normal-state-map (kbd "\C-e") 'er/expand-region)
-    (define-key evil-visual-state-map (kbd "\C-e") 'er/expand-region)))
-
-(defun er/add-text-mode-expansions ()
-  "This way we can also expand the region into paragraphs & pages in text mode.
-Directly taken from: https://github.com/magnars/expand-region.el."
-
-  (set (make-local-variable 'er/try-expand-list) (append
-                                                  er/try-expand-list
-                                                  '(mark-paragraph
-                                                    mark-page))))
-
-(add-hook 'text-mode-hook 'er/add-text-mode-expansions)
-
-
- -

-Editing files as root is a bit of a pain because usually the root user doesn't -have the same configuration as the current one, and attempting to do so can be -messy. So, instead of that, we could advice the find-file function so if the -file is not writable by the current user, then GNU Emacs will ask for editing -this same file as root: -

- -
- -
(defadvice find-file (after find-file-sudo activate)
-  "Find file as root if necessary."
-  (if (and buffer-file-name
-           (not (file-writable-p buffer-file-name)))
-    (if (yes-or-no-p "Do you want to edit this file as root?")
-        (find-alternate-file (concat "/sudo:root@localhost:" buffer-file-name)))))
-
-
- -

-YASnippet allows people to define shortcuts for writing some common blocks. -Moreover, it comes with a set of builtin snippets already. Since I don't -remember some of these snippets, I've mapped , h to -yas-describe-tables, which shows the available snippets in another buffer. -

- -
- -
(use-package yasnippet
-  :ensure t
-  :diminish yas-minor-mode
-  :init (yas-global-mode)
-  :config
-  (yas-global-mode 1)
-  (with-eval-after-load 'evil-leader
-    (evil-leader/set-key "h" 'yas-describe-tables)))
-
-
- -

-bool-flip is a very simple utility that toggles truthy/falsey values. -

- -
- -
(use-package bool-flip
-  :ensure t
-  :config
-  (global-set-key (kbd "C-c b") 'bool-flip-do-flip))
-
-
-
-
- -
-

Dired

-
-

-I use dired mode mainly for attaching document into emails. That being said, -whenever I use it, I want basic evil movement. -

- -
- -
(with-eval-after-load 'evil
-  (evil-add-hjkl-bindings dired-mode-map 'normal
-    (kbd "w") 'evil-forward-word-begin))
-
-
- -

-I also extend dired with some handy tweaks. -

- -
- -
(setq directory-free-space-args "-Pkh"
-      dired-dwim-target t
-      dired-omit-mode nil
-      dired-recursive-copies 'always
-      dired-recursive-deletes 'always
-      delete-old-versions t)
-
-
- -

-And now instruct dired mode how to attach files when using mu4e. This is taken -from the mu4e documentation, and it's available by typing -C-c RET C-a. -

- -
- -
(require 'gnus-dired)
-
-;; Make the `gnus-dired-mail-buffers' function also work on message-mode derived
-;; modes, such as mu4e-compose-mode.
-(defun gnus-dired-mail-buffers ()
-  "Return a list of active message buffers."
-
-  (let (buffers)
-    (save-current-buffer
-      (dolist (buffer (buffer-list t))
-        (set-buffer buffer)
-        (when (and (derived-mode-p 'message-mode)
-                (null message-sent-message-via))
-          (push (buffer-name buffer) buffers))))
-    (nreverse buffers)))
-
-(setq gnus-dired-mail-mode 'mu4e-user-agent)
-(add-hook 'dired-mode-hook 'turn-on-gnus-dired-mode)
-
-
-
-
- -
-

Evil

-
-

-Forgive me, Father, for I have sinned. I've been exposed to modal editing -through Vim, and that has changed how I view editing for the foreseeable future. -Because of this, I use Evil. The following blocks include some heavy-lifting so -Evil and GNU Emacs work without hitting each other, and it also includes some -Evil extensions. -

- -

-First of all, let's define a function that will be called whenever Evil is loaded. -

- -
- -
(defun mssola-evil ()
-  "Configure evil mode."
-
-  ; We can safely remap <C-u> because the counting will be handled a-la Vim.
-  (define-key evil-normal-state-map (kbd "C-u") 'evil-scroll-up)
-
-  ; Make window navigation easier.
-  (define-key evil-normal-state-map (kbd "C-j") 'evil-window-down)
-  (define-key evil-normal-state-map (kbd "C-k") 'evil-window-up)
-  (define-key evil-normal-state-map (kbd "C-l") 'evil-window-right)
-  (define-key evil-normal-state-map (kbd "C-h") 'evil-window-left)
-
-  ; The window navigation tweaks effectively wipe out the help prefix, which
-  ; is bad. Fortunately we can workaround this by providing "M-h" as the new
-  ; help prefix. This prefix is only used in emacs mode to mark lines, which is
-  ; something already handled by Evil.
-  (define-key global-map (kbd "M-h") 'help-command)
-  (fset 'help-command help-map)
-
-  ; I use the Super key in combination with j & k to move around i3. Let's unset
-  ; M- combos for these two fellows for whenever I misstype them.
-  (global-unset-key (kbd "M-j"))
-  (global-unset-key (kbd "M-k"))
-
-  ; both this function and the subsequent lines about [escape] are taken from
-  ; @aaronbieber configuration.
-  (defun minibuffer-keyboard-quit ()
-    "Abort recursive edit.
-In Delete Selection mode, if the mark is active, just deactivate it;
-then it takes a second \\[keyboard-quit] to abort the minibuffer."
-    (interactive)
-    (if (and delete-selection-mode transient-mark-mode mark-active)
-        (setq deactivate-mark  t)
-      (when (get-buffer "*Completions*") (delete-windows-on "*Completions*"))
-      (abort-recursive-edit)))
-
-  ;; Make escape quit everything, whenever possible.
-  (define-key evil-normal-state-map [escape] 'keyboard-quit)
-  (define-key evil-visual-state-map [escape] 'keyboard-quit)
-  (define-key minibuffer-local-map [escape] 'minibuffer-keyboard-quit)
-  (define-key minibuffer-local-ns-map [escape] 'minibuffer-keyboard-quit)
-  (define-key minibuffer-local-completion-map [escape] 'minibuffer-keyboard-quit)
-  (define-key minibuffer-local-must-match-map [escape] 'minibuffer-keyboard-quit)
-  (define-key minibuffer-local-isearch-map [escape] 'minibuffer-keyboard-quit)
-
-  ; I store macros on the <q> register for convenience, so I used to use the
-  ; <C-q> combo to execute this macro in Vim. In Emacs though, this combo is
-  ; reserved to a rather useful function, and I'd like to keep it that way. So,
-  ; now the mapping is set to <C-2> (mnemonic: where the @ symbol is). Moreover,
-  ; it's applied as many times as specified by the numeric prefix argument.
-  (define-key evil-normal-state-map (kbd "C-2")
-    (lambda (n)
-      (interactive "p")
-      (evil-execute-macro n "@q")))
-
-  ; C-s: switch to normal mode and save the buffer. I know :)
-  (define-key evil-normal-state-map (kbd "C-s") 'save-buffer)
-  (define-key evil-insert-state-map (kbd "C-s")
-    (lambda () (interactive) (save-buffer) (evil-force-normal-state))))
-
-
- -

-Now make sure that Evil is installed, and call the relevant configuration functions. -

- -
- -
(use-package evil
-  :ensure t
-  :config
-
-  (add-hook 'evil-mode-hook 'mssola-evil)
-  (evil-mode 1)
-
-  ;; C-z is unused and it's close to my beloved C-c. Since I don't want to mess
-  ;; with one of the most sacred Emacs prefixes, I'm moving to C-z.
-  (define-key key-translation-map (kbd "C-z") [escape])
-  (define-key evil-operator-state-map (kbd "C-z") 'keyboard-quit)
-  (set-quit-char "C-z")
-
-  ;; Use the proper initial evil state for the following modes.
-  (evil-set-initial-state 'help-mode 'normal)
-  (evil-set-initial-state 'debugger-mode 'normal)
-  (evil-set-initial-state 'describe-mode 'normal)
-  (evil-set-initial-state 'Buffer-menu-mode 'normal)
-
-
- -

-If Evil was properly loaded, then make sure that the following Evil-related -packages are installed and configured as well. I start by defining the -evil-leader package, which brings the leader feature from -Vim into Evil. -

- -
- -
(use-package evil-leader
-  :ensure t
-  :config
-  (global-evil-leader-mode)
-  (evil-leader/set-leader ",")
-  (setq evil-leader/in-all-states 1)
-  (evil-leader/set-key
-    "," 'back-to-indentation
-    "c" 'delete-window
-    "k" 'kill-buffer-and-window
-    "v" 'split-window-right
-    "V" (lambda () (interactive) (split-window-right) (other-window 1))
-    "f" 'flycheck-list-errors
-    "e" 'eval-last-sexp
-    "b" 'view-buffer
-    "o" 'browse-url-at-point))
-
-
- -

-Another handy Vim plugin that has made it into Evil is evil-surround, which -defines a new text object for surrounding characters (e.g. change a string from -having double quotes with single quotes in a single command). -

- -
- -
(use-package evil-surround
-  :ensure t
-  :config
-  (global-evil-surround-mode 1))
-
-
- -

-Next is another Vim plugin that has been ported to Evil: evil-commentary. This -package defines a new motion for comments, which is bound to -gc. So, for example, gcc will comment -the current line, regardless of the programming language. -

- -
- -
(use-package evil-commentary
-  :ensure t
-  :config
-  (evil-commentary-mode t))
-
-
- -

-Another cool package is evil-args which defines the argument text object. This -text object can be targeted with the a character, and we can move backward and -forward through arguments with H and L -respectively. -

- -
- -
(use-package evil-args
-  :ensure t
-  :config
-  ; Configuration taken from the documentation of evil-args.
-
-  ;; Bind evil-args text objects
-  (define-key evil-inner-text-objects-map "a" 'evil-inner-arg)
-  (define-key evil-outer-text-objects-map "a" 'evil-outer-arg)
-
-  ;; Bind evil-forward/backward-args
-  (define-key evil-normal-state-map "L" 'evil-forward-arg)
-  (define-key evil-normal-state-map "H" 'evil-backward-arg)
-  (define-key evil-motion-state-map "L" 'evil-forward-arg)
-  (define-key evil-motion-state-map "H" 'evil-backward-arg))
-
-
- -

-Last but not least, evil-numbers brings a couple of bindings available to Vim -into Evil: C-a for increasing a number, and -C-c - for decreasing it (modified because -C-z is my escape sequence). -

- -
- -
(use-package evil-numbers
-  :ensure t
-  :config
-  (define-key evil-normal-state-map (kbd "C-a") 'evil-numbers/inc-at-pt)
-  (define-key evil-normal-state-map (kbd "C-c -") 'evil-numbers/dec-at-pt)))
-
-
-
-
- -
-

Magit

-
-

-A git porcelain for GNU Emacs. Even if I'm still using the git CLI, it's -certainly useful for some common tasks (I guess that I still need some learning). -

- -
- -
(use-package magit
-  :ensure t
-  :config
-
-
- -

-In some cases normal mode is not the right mode (e.g. commit mode). For these -cases, set the proper default mode. -

- -
- -
(with-eval-after-load 'evil
-  (add-hook 'git-commit-mode-hook 'evil-insert-state)
-  (evil-set-initial-state 'magit-log-edit-mode 'insert))
-
-
- -

-When showing the status, hide the usually-redundant "branch" section and show -the rest. -

- -
- -
(add-hook 'magit-section-set-visibility-hook
-          '(lambda (section)
-             (if (string= (magit-section-type section) "branch")
-                 'hide
-               'show)))
-
-
- -

-Set a key binding for magit-log-buffer-file. -

- -
- -
(global-set-key (kbd "C-c l") 'magit-log-buffer-file)
-
-
- -

-And repair some key bindings from Evil mode. -

- -
- -
(with-eval-after-load 'evil-leader
-  (evil-leader/set-key "s" 'magit-status)
-
-  (use-package evil-magit
-    :ensure t
-    :config
-
-    ; The magit + evil-magit combo messes up some chords, let's fix this.
-    (evil-define-key 'normal magit-mode-map
-      "\C-h" 'evil-window-left
-      "\C-l" 'evil-window-right
-      "\C-j" 'evil-window-down
-      "\C-k" 'evil-window-up
-      "\M-p"  'helm-projectile-switch-project))))
-
-
-
-
- -
-

mu4e

-
-

-I use mu and mu4e to manage my email. The configuration for this has been taken -mainly from the documentation, plus some cool remarks on Reddit. This -configuration makes quite some assumptions. Read the emacs/README.org file as -provided in my dotfiles project to get more details. -

- -

-I'm using an RPM that I've built on OBS which installs mu4e globally. -

- -
- -
(add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e")
-(require 'mu4e)
-
-(when (featurep 'mu4e)
-
-
- -

-Diferent SMTP options that will be used for each context. -

- -
- -
(setq message-send-mail-function 'smtpmail-send-it
-      mu4e-maildir (expand-file-name "~/.mail")
-      starttls-use-gnutls t)
-
-
- -

-After that, I am defining some functions that will be used in various parts of -the configuration. -

- -
- -
(defun mssola-smtp (server port)
-  "Set SMTP variables depending on the given SERVER and PORT."
-
-  (require 'smtpmail)
-
-  (setq smtpmail-starttls-credentials
-        '((server port nil nil))
-        smtpmail-auth-credentials
-        (expand-file-name "~/.authinfo.gpg")
-        smtpmail-default-smtp-server server
-        smtpmail-smtp-server server
-        smtpmail-smtp-service port))
-
-; https://www.reddit.com/r/emacs/comments/47t9ec/share_your_mu4econtext_configs/d0fsih6
-(defun mu4e-message-maildir-matches (msg rx)
-  "Returns true if the maildir of MSG matches the given regexp RX."
-
-  (when rx
-    (if (listp rx)
-        ;; if rx is a list, try each one for a match
-        (or (mu4e-message-maildir-matches msg (car rx))
-            (mu4e-message-maildir-matches msg (cdr rx)))
-      ;; not a list, check rx
-      (string-match rx (mu4e-message-field msg :maildir)))))
-
-(defun suse-refile-folder (key)
-  "Returns the refile folder for the given SUSE account in the KEY arg"
-  (concat "/" key "/Archives/"
-          (format-time-string "%Y" (current-time))))
-
-
- -

-Now it's time to define the different contexts that I have. Defining contexts -this way is relatively new (since mu 0.9.16). -

- -
- -
(setq mu4e-contexts
-      `(
-        ;; GMail
-        ,(make-mu4e-context
-          :name "gmail"
-          :enter-func (lambda ()
-                        (mu4e-message "Switching to gmail.com")
-                        (mssola-smtp "smtp.gmail.com" 587))
-          :match-func (lambda (msg)
-                        (when msg
-                          (mu4e-message-maildir-matches msg "^/gmail")))
-          :vars '(
-                  (user-mail-address     . "mikisabate@gmail.com")
-                  (mu4e-reply-to-address . "mikisabate@gmail.com")
-                  (mu4e-drafts-folder    . "/gmail/Drafts")
-                  (mu4e-sent-folder      . "/gmail/Sent")
-                  (mu4e-refile-folder    . "/gmail/All")
-                  (mu4e-trash-folder     . "/gmail/Trash")))
-
-        ;; suse.com
-        ,(make-mu4e-context
-          :name "comsuse"
-          :enter-func (lambda ()
-                        (mu4e-message "Switching to suse.com")
-                        (mssola-smtp "smtp.novell.com" 25))
-          :match-func (lambda (msg)
-                        (when msg
-                          (mu4e-message-maildir-matches msg "^/susecom")))
-          :vars `(
-                  (user-mail-address     . "msabate@suse.com")
-                  (mu4e-reply-to-address . "msabate@suse.com")
-                  (mu4e-drafts-folder    . "/susecom/Drafts")
-                  (mu4e-sent-folder      . "/susecom/Sent")
-                  (mu4e-refile-folder    . ,(suse-refile-folder "susecom"))
-                  (mu4e-trash-folder     . "/susecom/Trash")))
-
-        ;; suse.de
-        ,(make-mu4e-context
-          :name "desuse"
-          :enter-func (lambda ()
-                        (mu4e-message "Switching to suse.de")
-                        (mssola-smtp "imap.suse.de" 587))
-          :match-func (lambda (msg)
-                        (when msg
-                          (mu4e-message-maildir-matches msg "^/susede")))
-          :vars `(
-                  (user-mail-address     . "msabate@suse.de")
-                  (mu4e-reply-to-address . "msabate@suse.de")
-                  (mu4e-drafts-folder    . "/susede/Drafts")
-                  (mu4e-sent-folder      . "/susede/Sent")
-                  (mu4e-refile-folder    . ,(suse-refile-folder "susede"))
-                  (mu4e-trash-folder     . "/susede/Trash")))))
-
-
- -

-If mu4e cannot figure things out, ask me. -

- -
- -
(setq mu4e-context-policy 'ask)
-(setq mu4e-compose-context-policy 'ask)
-
-
- -

-Fill the mu4e-user-mail-address-list variable with the contexts. -

- -
- -
(setq mu4e-user-mail-address-list
-      (delq nil
-            (mapcar (lambda (context)
-                      (when (mu4e-context-vars context)
-                        (cdr (assq 'user-mail-address
-                                   (mu4e-context-vars context)))))
-                    mu4e-contexts)))
-
-
- -

-Setting my bookmarks -

- -
- -
(setq mu4e-bookmarks
-      '(("maildir:/gmail/inbox OR maildir:/susecom/inbox OR maildir:/susede/inbox" "Inbox Folders" ?n)
-        ("maildir:/gmail/Sent OR maildir:/susecom/Sent OR maildir:/susede/Sent" "Sent Folders" ?s)
-        ("flag:unread AND NOT flag:trashed" "Unread messages" ?u)
-        ("date:today..now" "Today's messages" ?t)))
-
-
- -

-The following signature looks alright regardless of whether the client supports -format=flowed or not. -

- -
- -
(setq mu4e-compose-signature
-      (concat
-       "Miquel Sabaté Solà,\n"
-       "PGP: 4096R / 1BA5 3C7A C93D CA2A CFDF DA97 96BE 8C6F D89D 6565\n"))
-
-
- -

-Sign outgoing emails always. -

- -
- -
(add-hook 'message-send-hook 'mml-secure-message-sign-pgpmime)
-
-
- -

-To avoid UID clashes. See this. -

- -
- -
(setq mu4e-change-filenames-when-moving t)
-
-
- -

-Miscellaneous settings. -

- -
- -
(setq mu4e-html2text-command "w3m -T text/html"
-      mu4e-attachment-dir  "~/Downloads"
-      mu4e-headers-date-format "%Y-%m-%d %H:%M"
-      message-citation-line-format "%N @ %Y-%m-%d %H:%M %Z:\n"
-      message-citation-line-function 'message-insert-formatted-citation-line
-      message-kill-buffer-on-exit t
-      mu4e-get-mail-command "mbsync -aqV"
-      mu4e-update-interval 600
-      mu4e-compose-dont-reply-to-self t
-      mu4e-compose-format-flowed t
-      mu4e-headers-skip-duplicates t
-      mu4e-headers-include-related t
-      mu4e-headers-auto-update t)
-
-
- -

-The headers to show in the headers list a pair of a field and its width, -with `nil' meaning 'unlimited' (better only use that for the last field. -These are the defaults: -

- -
- -
(setq mu4e-headers-fields
-      '( (:date          .  18)
-         (:mailing-list  .  15)
-         (:from-or-to    .  20)
-         (:subject       .  nil)))
-
-
- -

-Show images -

- -
- -
(setq mu4e-view-show-images t
-      mu4e-view-image-max-width 800)
-
-; Use imagemagick, if available
-(when (fboundp 'imagemagick-register-types)
-  (imagemagick-register-types))
-
-
- -

-As of 0.9.18 and GNU Emacs 25, the mu4e-action-with-xwidget can be used to -render an HTML message with Webkit. -

- -
- -
(if (>= emacs-major-version 25)
-    (add-to-list 'mu4e-view-actions
-                 '("webkit" . mu4e-action-view-with-xwidget)))
-
-
- -

-Look for mu4e-msg2pdf in the exec path. The reason for this is that the OBS -package installs mu's toys into the exec path, but mu4e doesn't really count -on it. -

- -
- -
(let ((exec (locate-file "msg2pdf" exec-path exec-suffixes)))
-  (if exec
-      (setq mu4e-msg2pdf exec)))
-
-
- -

-Adding hooks for composing and viewing messages. -

- -
- -
(defun mssola-compose-mode ()
-  "My settings for message composition."
-
-  ; If we are composing an email from scratch, it's more convenient to be in
-  ; insert mode. Otherwise start with normal mode.
-  (with-eval-after-load 'evil
-    (if mu4e-compose-parent-message
-        (evil-set-initial-state 'mu4e-compose-mode 'normal)
-      (evil-set-initial-state 'mu4e-compose-mode 'insert)))
-
-  ; Guess hard newlines
-  (use-hard-newlines t 'guess)
-
-  ; So it's easy to encrypt/decrypt emails.
-  (epa-mail-mode)
-
-  ; Spellz
-  (flyspell-mode))
-
-(add-hook 'mu4e-compose-mode-hook 'mssola-compose-mode)
-
-; I want to read messages in the format that the sender used. I'm also
-; enabling epa-mail-mode, so it's easy to decrypt received emails.
-(add-hook 'mu4e-view-mode-hook
-          (lambda ()
-            (epa-mail-mode)
-            (visual-line-mode 1)))
-
-
- -

-I want desktop notifications when receiving email. -

- -
- -
(use-package mu4e-alert
-  :ensure t
-  :config
-
-  ; Notify me for unread emails from my inbox.
-  (mu4e-alert-set-default-style 'libnotify)
-  (add-hook 'after-init-hook #'mu4e-alert-enable-notifications)
-  (add-hook 'after-init-hook #'mu4e-alert-enable-mode-line-display)
-  (setq mu4e-alert-interesting-mail-query
-        (concat
-         "(maildir:/gmail/inbox OR maildir:/susecom/inbox OR maildir:/susede/inbox) "
-         "AND flag:unread AND NOT flag:trashed"))
-  (setq mu4e-alert-email-notification-types '(count)))
-
-; Evil mode in mu4e
-(with-eval-after-load 'evil
-  (use-package evil-mu4e
-    :ensure t
-    :config
-
-    ; Idea taken from evil-mu4e.el
-    (defvar mssola-evil-mu4e-mode-map-bindings
-      `((,evil-mu4e-state mu4e-headers-mode-map "\C-u" evil-scroll-up)
-        (,evil-mu4e-state mu4e-main-mode-map    "\C-u" evil-scroll-up)
-        (,evil-mu4e-state mu4e-view-mode-map    "h" evil-backward-char)))
-
-    (dolist (binding mssola-evil-mu4e-mode-map-bindings)
-      (evil-define-key
-        (nth 0 binding) (nth 1 binding) (nth 2 binding) (nth 3 binding)))))
-
-
- -

-And finally define a proper shortcut. -

- -
- -
; The trailing parenthesis closes the "(when (featurep 'mu4e)" statement from
-; the very beginning.
-(global-set-key (kbd "C-c m") 'mu4e))
-
-
-
-
- -
-

org

-
-

-org mode is an incredible tool that keeps me organized: TODOs, notes, agenda, -etc. Moreover, it's built in GNU Emacs: -

- -
- -
(require 'org)
-
-
-
- -
-

General settings

-
-

-First of all, let me define some helper functions. -

- -
- -
(defun mssola-org-skip-if-priority (priority &optional subtree)
-  "Skip an agenda item if it has a priority of PRIORITY.
-PRIORITY may be one of the characters ?A, ?B, or ?C.
-Skips the current entry unless SUBTREE is not nil.  This function has been
-copied from @aaronbieber."
-
-  (let ((end (if subtree (save-excursion (org-end-of-subtree t))
-               (save-excursion (progn (outline-next-heading) (1- (point))))))
-        (pri-value (* 1000 (- org-lowest-priority priority)))
-        (pri-current (org-get-priority (thing-at-point 'line t))))
-    (if (= pri-value pri-current)
-        end
-      nil)))
-
-(defun mssola-org-skip-if-not-closed-in-day (time &optional subtree)
-  "Skip entries that were not closed in the given TIME.
-Skip the current entry unless SUBTREE is not nil, in which case skip
-the entire subtree.  Idea taken from @aaronbieber"
-
-  (let ((end (if subtree (save-excursion (org-end-of-subtree t))
-               (save-excursion (progn (outline-next-heading) (1- (point))))))
-        (day-prefix (format-time-string "%Y-%m-%d" time)))
-
-    (if (save-excursion
-          (and (re-search-forward org-closed-time-regexp end t)
-               (string= (substring (match-string-no-properties 1) 0 10) day-prefix)))
-        nil
-      end)))
-
-
- -

-Some general UI settings for org mode. -

- -
- -
(setq org-src-tab-acts-natively t
-      org-confirm-babel-evaluate nil
-      org-edit-src-content-indentation 0)
-
-(setq org-todo-keywords
-      '((sequence "TODO(t)"  "|"  "DONE(d!)")
-        (sequence "IDEA(i)"  "WORKING(w)"  "|"  "USED(u@/!)"  "DISCARDED(x@/!)")))
-
-(setq org-todo-keyword-faces
-      '(("TODO"      . org-todo)
-        ("IDEA"      . font-lock-constant-face)
-        ("WORKING"   . font-lock-constant-face)
-        ("DONE"      . org-done)
-        ("USED"      . org-done)
-        ("DISCARDED" . org-done)))
-
-
- -

-Logging settings. -

- -
- -
(setq org-log-done t)
-(setq org-log-redeadline (quote time))
-(setq org-log-reschedule (quote time))
-
-
- -

-Where org files reside. -

- -
- -
(setq org-agenda-files '("~/org/"))
-
-
-
-
- -
-

Publishing

-
-

-In order to publish files into HTML, I would like to have htmlize installed. -This package allows org to export to HTML in a better way (e.g. allowing code -blocks to be converted into HTML as well, so we can properly colorize it). -

- -
- -
(use-package htmlize
-  :ensure t)
-
-
- -

-And now let's set all the related settings. -

- -
- -
(setq org-src-fontify-natively t
-      org-html-include-timestamps nil
-      org-html-toplevel-hlevel 2
-      org-html-htmlize-output-type 'css
-      org-export-with-section-numbers nil
-      org-export-with-sub-superscripts nil
-      org-export-htmlize-output-type 'css)
-
-
- -

-Sometimes it's useful to export to LaTeX. That is, when you are simply writing a -quick document that will end up being converted into LaTeX and finally into PDF: -

- -
- -
(require 'ox-latex)
-
-(unless (boundp 'org-latex-classes)
-  (setq org-latex-classes nil))
-
-(add-to-list 'org-latex-classes
-             '("article"
-               "\\documentclass{article}"
-               ("\\section{%s}" . "\\section*{%s}")
-               ("\\subsection{%s}" . "\\subsection*{%s}")
-               ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
-               ("\\paragraph{%s}" . "\\paragraph*{%s}")
-               ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
-
-
- -

-You can also export org documents to man pages. In order to do so, you have to -perform this first: -

- -
- -
(require 'ox-man)
-
-
-
-
- -
-

Agenda

-
-

-Custom commands for org-agenda. -

- -
- -
(setq org-agenda-custom-commands
-      '(("p" "Printed agenda"
-         ; Daily agenda with a 2-weeks deadline warning. Tasks are
-         ; represented as [ ] items.
-         ((agenda ""
-                  ((org-agenda-ndays 1)
-                   (org-deadline-warning-days 14)
-                   (org-agenda-todo-keyword-format "[ ]")
-                   (org-agenda-scheduled-leaders '("" ""))))
-
-         ; Display a "High Priority" list of tasks on top.
-          (tags "PRIORITY=\"A\""
-                ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
-                 (org-agenda-sorting-strategy '(tag-up priority-down))
-                 (org-agenda-todo-keyword-format "")
-                 (org-agenda-overriding-header "\nHigh priority\n--------------\n")))
-
-
-          ; All tasks except those already listed as high priority or
-          ; ideas. Scheduled and deadlines are also ignored here.
-          (alltodo ""
-                   ((org-agenda-skip-function '(or (mssola-org-skip-if-priority ?A)
-                                                   (org-agenda-skip-entry-if 'todo '("IDEA" "WORKING"))
-                                                   (org-agenda-skip-if nil '(scheduled deadline))))
-                    (org-agenda-sorting-strategy '(tag-up priority-down))
-                    (org-agenda-todo-keyword-format "")
-                    (org-agenda-overriding-header "\nAll tasks\n----------\n")))
-
-          ; List of ideas.
-          (todo "IDEA"
-                ((org-agenda-overriding-header "\nIdeas\n------\n")
-                 (org-agenda-todo-keyword-format ""))))
-
-         ((org-agenda-compact-blocks t)
-          (org-agenda-remove-tags t)))
-
-        ; List of done items. Useful for standups, review meetings, weekly
-        ; reports, etc.
-        ("d" "Done items"
-         ; First show the items done yesterday. Useful for standups.
-         ((todo "DONE"
-                ((org-agenda-overriding-header "Done yesterday\n---------------\n")
-                 (org-agenda-skip-function
-                  '(mssola-org-skip-if-not-closed-in-day
-                    (time-subtract (current-time) (seconds-to-time 86400))))
-                 (org-agenda-todo-keyword-format "")))
-
-          ; Then show what I've done today.
-          (todo "DONE"
-                ((org-agenda-overriding-header "\nDone today\n-----------\n")
-                 (org-agenda-skip-function
-                  '(mssola-org-skip-if-not-closed-in-day
-                    (current-time)))
-                 (org-agenda-todo-keyword-format "")))
-
-          ; Finally show what I've been doing in the past 15 days. Useful for
-          ; review meetings and weekly reports.
-          (todo "DONE"
-                ((org-agenda-start-day "-15d")
-                 (org-agenda-span 15)
-                 (org-agenda-start-on-weekday nil)
-                 (org-agenda-todo-keyword-format "")
-                 (org-agenda-scheduled-leaders '("" ""))
-                 (org-agenda-overriding-header "\nDone during the past 15 days\n-----------------------------\n"))))
-
-         ((org-agenda-compact-blocks t)
-          (org-agenda-remove-tags t)))))
-
-
- -

-The prefix for the different kinds of types being used. -

- -
- -
(setq org-agenda-prefix-format '((agenda . "%t%s")
-                                 (tags   . "%c:%s")
-                                 (todo   . "%c:%t%s")))
-
-
- -

-Set up a key binding for org-agenda. -

- -
- -
(global-set-key (kbd "C-c a") 'org-agenda)
-
-
-
-
- -
-

Capture

-
-

-Set the default notes file and the key binding. -

- -
- -
(setq org-default-notes-file (concat org-directory "/notes.org"))
-(define-key global-map "\C-cc" 'org-capture)
-
-
- -

-And finally set org-capture-templates. -

- -
- -
(setq org-capture-templates
-      `(("t" "todo" entry (file "") "* TODO %?\n%U\n")
-        ("i" "idea" entry (file "") "* %? :IDEA:\n%U\n%a\n")))
-
-
-
-
- -
-

Other

-
-

-Insert a <kbd></kbd> value in org mode. See this StackExchange answer. -

- -
- -
(defun endless/insert-key (key)
-  "Ask for a key then insert its description.
-Will work on both org-mode and any mode that accepts plain html."
-  (interactive "kType key sequence: ")
-  (let* ((is-org-mode (derived-mode-p 'org-mode))
-         (tag (if is-org-mode
-                  "@@html:<kbd>%s</kbd>@@"
-                "<kbd>%s</kbd>")))
-    (if (null (equal key "\r"))
-        (insert
-         (format tag (help-key-description key nil)))
-      (insert (format tag ""))
-      (forward-char (if is-org-mode -8 -6)))))
-
-(define-key org-mode-map "\C-ck" #'endless/insert-key)
-
-
-
-
- -
-

TODO shortcut for making an org link, and transforming a link into a proper org link

-
-
-

TODO make it work with evil

-
-
-

TODO Proper keybindings for quick access.

-
- -
-

TODO shortcuts for stuff like: create something urgent for today

-
-
- -
-

IRC

-
-

-I'm using ERC for IRC. -

- -
- -
(use-package erc
-  :config
-
-
- -

-First of all, let's add some basic modules. -

- -
- -
(dolist (mod '(autojoin track truncate))
-  (add-to-list 'erc-modules mod))
-
-
- -

-Setting up basic stuff. -

- -
- -
(setq erc-hide-list '("PART")
-      erc-prompt (lambda () (concat (buffer-name) ">"))
-      erc-track-exclude-types '("JOIN" "NICK" "PART" "QUIT" "MODE")
-      erc-server-coding-system '(utf-8 . utf-8)
-      erc-kill-buffer-on-part t
-      erc-kill-queries-on-quit t
-      erc-kill-server-buffer-on-quit t
-      erc-fill-column 100
-      erc-fill-prefix ""
-      erc-timestamp-format "[%H:%M] "
-      erc-insert-timestamp-function 'erc-insert-timestamp-left
-      erc-insert-away-timestamp-function 'erc-insert-timestamp-left
-      erc-hide-timestamps nil
-      erc-whowas-on-nosuchnick t
-      erc-public-away-p nil
-      erc-echo-notice-always-hook '(erc-echo-notice-in-minibuffer)
-      erc-auto-set-away nil
-      erc-autoaway-message "%i seconds out..."
-      erc-away-nickname "msabate"
-      erc-enable-logging t
-      erc-query-on-unjoined-chan-privmsg t)
-
-
- -

-Let's log messages whenever I receive/send them. The other option is to only do -that on /quit or /part, but it's better to be safe than sorry. -

- -
- -
(require 'erc-log)
-(erc-log-enable)
-
-(setq erc-log-channels-directory "~/.emacs.d/erc"
-      erc-save-buffer-on-part nil
-      erc-save-queries-on-quit nil
-      erc-log-write-after-send t
-      erc-log-write-after-insert t)
-
-
- -

-Servers and channels to auto-join. -

- -
- -
(setq erc-autojoin-channels-alist
-      '(("irc.freenode.net" "#gnu" "#emacs")
-        ("irc.suse.de" "#suse" "#docker")))
-
-
- -

-Use the erc-hl-nicks package, so highlight support for nicknames is better. -

- -
- -
(use-package erc-hl-nicks
-  :ensure t
-  :init
-  (with-eval-after-load 'erc
-    (add-to-list 'erc-modules 'hl-nicks)))
-
-
- -

-I want to have a desktop notification whenever someone mentions my name. For -this, I'm using the erc-notifications package which is built in ERC since -GNU Emacs 24.3. -

- -
- -
(with-eval-after-load 'erc
-  (setq erc-notifications-icon
-        (concat
-         "/usr/share/emacs/"
-         (format "%s.%s" emacs-major-version emacs-minor-version)
-         "/etc/images/icons/hicolor/24x24/apps/emacs.png"))
-  (add-to-list 'erc-modules 'notifications))
-
-
- -

-At this point, we can safely update all the loaded ERC modules. -

- -
- -
(add-hook 'erc-connect-pre-hook
-          (lambda (x) (erc-update-modules)))
-
-
- -

-Start some modules which won't do it by default. Moreover, according to the wiki -auto-fill-mode should be disabled if I'm using erc-fill-mode. -

- -
- -
(add-hook 'erc-mode-hook
-          '(lambda ()
-             (erc-track-mode t)
-             (auto-fill-mode -1)
-             (erc-log-mode 1)
-             (erc-autojoin-mode 1)))
-
-
- -

-And now define a function to connect to both IRC servers. -

- -
- -
(defun mssola-erc ()
-  "Join pre-specified servers and channels."
-
-  (interactive)
-
-  (erc :server "irc.freenode.net" :port 6667 :nick "mssola")
-  (erc-tls :server "irc.suse.de" :port 6697 :nick "mssola"))
-
-(global-set-key (kbd "C-c i") 'mssola-erc))
-
-
-
-
- -
-

Languages

-
-
-

General

-
-

-First of all, define a function that identifies some warning keywords -(e.g. TODO). This function can then be applied to the proper mode. -

- -
- -
(defun warnings-mode-hook ()
-  "Hook for enabling the warning face on strings with a warning prefix."
-
-  (font-lock-add-keywords nil
-    '(("\\(XXX\\|FIXME\\|TODO\\|HACK\\|NOTE\\)"
-    1 font-lock-warning-face prepend))))
-
-
- -

-Text mode is not a programming language, but it's used quite often in this -context too. In this case, I want spell check and wc-mode activated. -

- -
- -
(add-hook 'text-mode-hook
-          (lambda ()
-            (flyspell-mode 1)
-            (wc-mode 1)))
-
-
-
-
- -
-

Shell

-
-
- -
(use-package bats-mode
-  :ensure t)
-
-
-
-
- -
-

Lisp

-
-

-Emacs lisp needs rainbow-delimiters, so the amount of parenthesis is less -confusing. Moreover, I'm also enabling eldoc-mode and the aforementioned -warnings-mode-hook. -

- -
- -
(add-hook 'emacs-lisp-mode-hook
-          (lambda ()
-            (eldoc-mode 1)
-            (warnings-mode-hook)
-            (rainbow-delimiters-mode 1)
-            ; https://github.com/jhenahan/emacs.d/blob/master/emacs-init.org#emacs-lisp
-            (setq mode-name "ξ")))
-
-
-
-
- -
-

C and C++

-
-

-C and C++ only require the warnings-mode-hook function, spell checking for the -comments and the usage of tabs instead of spaces. -

- -
- -
; Note that C-common includes languages with a similar syntax of C.
-(add-hook 'c-mode-common-hook 'warnings-mode-hook)
-(add-hook 'c-mode-common-hook (lambda() (flyspell-prog-mode)))
-
-;; C
-(add-hook 'c-mode-hook
-  (lambda () (setq indent-tabs-mode t)))
-
-;; C++
-(add-hook 'c++-mode-hook
-  (lambda () (setq indent-tabs-mode t)))
-
-
- -

-CMake for y'all. -

- -
- -
(use-package cmake-mode
-  :ensure t
-  :config
-
-  (setq auto-mode-alist
-        (append
-         '(("CMakeLists\\.txt\\'" . cmake-mode))
-         '(("\\.cmake\\'" . cmake-mode))
-         auto-mode-alist))
-
-  (use-package cmake-font-lock
-    :ensure t
-    :config
-
-    (add-hook 'cmake-mode-hook 'cmake-font-lock-activate)
-    (add-hook 'yaml-mode-hook 'warnings-mode-hook)))
-
-
-
-
- -
-

Ruby

-
-

-Include warning keywords in Ruby. -

- -
- -
(add-hook 'ruby-mode-hook 'warnings-mode-hook)
-
-
-
-
- -
-

Go

-
-

-And now my Go configuration. This includes stuff like the usage of goimports, -gofmt on save, among many other useful things. -

- -
- -
(defun mssola-go-mode ()
-  "My configuration for Go mode."
-
-  ; Use goimports instead of go-fmt
-  (setq gofmt-command "goimports")
-
-  ; Call Gofmt before saving
-  (add-hook 'before-save-hook 'gofmt-before-save)
-
-  ; Integration flycheck with Go
-  (add-to-list 'load-path
-    (concat (getenv "GOPATH") "/src/github.com/dougm/goflymake"))
-  (require 'go-flycheck)
-
-  (evil-leader/set-key
-    "." 'godef-jump-other-window)
-
-  (setq indent-tabs-mode t)
-  (flyspell-prog-mode)
-
-  ; eldoc support
-  (use-package go-eldoc
-    :ensure t
-    :config
-    (require 'go-eldoc))
-
-  (use-package go-add-tags
-    :ensure t
-    :config
-    (evil-leader/set-key "t" 'go-add-tags)))
-
-;; Go
-(use-package go-mode
-  :ensure t
-  :pin melpa-stable
-  :config
-
-  (add-hook 'go-mode-hook 'warnings-mode-hook)
-  (add-hook 'go-mode-hook 'go-eldoc-setup)
-  (add-hook 'go-mode-hook 'mssola-go-mode))
-
-
-
-
- -
-

Rust

-
-

-Install rust-mode and add some hooks to make it friendlier. -

- -
- -
(use-package rust-mode
-  :ensure t
-  :config
-
-  (add-hook 'before-save-hook
-            #'(lambda ()
-                (when (eq major-mode 'rust-mode)
-                  (rust-format-buffer))))
-
-  (use-package flycheck-rust
-    :ensure t
-    :config
-
-    (add-hook 'flycheck-mode-hook #'flycheck-rust-setup)))
-
-
-
-
- -
-

Tabs vs spaces

-
-

-Tabs or spaces? Both. The smart-tabs-mode has the philosophy of: tabs for -indentation, spaces for alignment. This is only applied in languages where I'm -usings tabs for indentation (C, C++ and Go). -

- -
- -
(use-package smart-tabs-mode
-  :ensure t
-  :config
-  (smart-tabs-add-language-support golang go-mode-hook
-    ((c-indent-line . c-basic-offset)
-     (c-indent-region . c-basic-offset)))
-  (smart-tabs-insinuate 'c 'c++ 'golang))
-
-
-
-
- -
-

Inferior markup languages.

-
-
- -
;; Markdown mode with preview mode in the browser.
-(use-package markdown-mode
-  :ensure t
-  :config
-
-  ; This is the one that I got from openSUSE.
-  (custom-set-variables
-    '(markdown-command "/usr/bin/markdown-calibre"))
-
-  ; Preview mode does its things through websockets, so it's a requirement.
-  ; After that, we can safely require it.
-  (use-package websocket
-    :ensure t
-    :config
-    (use-package markdown-preview-mode
-      :ensure t)))
-
-; YAML
-(use-package yaml-mode
-  :ensure t
-  :config
-
-  (add-hook 'yaml-mode-hook 'warnings-mode-hook))
-
-
-
-
- -
-

Web-related stuff.

-
-

-Slim and SCSS. -

- -
- -
(use-package slim-mode
-  :ensure t)
-
-(use-package scss-mode
-  :ensure t
-  :config
-
-  (setq scss-compile-at-save nil)
-  (add-hook 'yaml-mode-hook 'warnings-mode-hook))
-
-(use-package coffee-mode
-  :ensure t)
-
-
- -

-Languages specific for backend code like PHP, and web-mode, which provides a -bundle of features which are interesting for web-related stuff. -

- -
- -
(use-package php-mode
-  :ensure t)
-
-(use-package web-mode
-  :ensure t
-  :config
-
-  (add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode))
-  (add-to-list 'auto-mode-alist '("\\.jinja\\'" . web-mode))
-  (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
-
-  (add-hook 'web-mode-hook
-            (lambda ()
-              (setq web-mode-markup-indent-offset 2)
-              (setq web-mode-css-indent-offset 2)
-              (setq web-mode-code-indent-offset 2)))
-
-  (add-hook 'js-mode-hook
-            (lambda ()
-              (setq js-indent-level 2)
-              (rainbow-delimiters-mode 1)))
-
-  (use-package vue-mode
-    :ensure t
-    :config
-    (setq mmm-submode-decoration-level 0))
-
-  ; React: treat it as a derived mode. Idea taken from spacemacs.
-  (define-derived-mode react-mode web-mode "react")
-  (add-to-list 'auto-mode-alist '("\\.jsx\\'" . react-mode))
-  (add-to-list 'auto-mode-alist '("\\.react.js\\'" . react-mode))
-
-  (add-hook 'react-mode-hook
-            (lambda ()
-              (yas-activate-extra-mode 'js-mode)
-              (web-mode-set-content-type "jsx")
-              (setq-local web-mode-enable-auto-quoting nil)
-              (rainbow-delimiters 1))))
-
-
- -

-The json-reformat package provides functions for reformatting JSON strings. It -happens from time to time that I have to read JSON output from responses, and it -can be frustrating without proper formatting. -

- -
- -
(use-package json-reformat
-  :ensure t)
-
-
-
-
- -
-

Devops

-
-

-Highlighting for Dockerfiles. -

- -
- -
(use-package dockerfile-mode
-  :ensure t
-  :config
-
-  (add-to-list 'auto-mode-alist '("Dockerfile\\'" . dockerfile-mode)))
-
-
- -

-Stuff from Hashicorp like terraform and HCL. -

- -
- -
(use-package terraform-mode
-  :ensure t
-  :config
-
-  (terraform-format-on-save-mode))
-
-(use-package hcl-mode
-  :ensure t)
-
-
- -
- -
(use-package salt-mode
-  :ensure t)
-
-
-
-
- -
-

Others

-
-

-The soria theme has the soria-purple-identifiers hook. This hook instructs -the theme to use purple for identifiers instead of the default color. This is a -remnant from my Vim times, and I only apply it to some languages (random -criteria really). -

- -
- -
(dolist (lang-hook '(ruby-mode-hook
-                     php-mode-hook
-                     perl-mode-hook
-                     emacs-lisp-mode-hook))
-  (add-hook lang-hook 'soria-purple-identifiers))
-
-
-
-
- -
-

LaTeX

-
-

-Let's use Auctex for LaTeX files. -

- -
- -
(use-package tex
-  :ensure auctex
-  :config
-  (setq TeX-auto-save t)
-  (setq TeX-parse-self t)
-  (setq-default TeX-master nil))
-
-
-
-
-
- -
-

WoMan

-
-

-WoMan is a package that is included inside of GNU Emacs by default, and that -takes care of visualizing man pages. Let's properly setup Evil mode for this: -

- -
- -
(with-eval-after-load "evil"
-  (evil-set-initial-state 'woman-mode 'normal)
-  (evil-define-key 'normal woman-mode-map
-    "J" 'Man-next-section
-    "K" 'Man-previous-section
-    "\C-h" 'evil-window-left
-    "\C-l" 'evil-window-right
-    "\C-j" 'evil-window-down
-    "\C-k" 'evil-window-up
-    "\C-u" 'evil-scroll-up))
-
-
- -

-Finally, I want man pages to fill all the frame: -

- -
- -
(setq woman-fill-frame t)
-
-
-
-
- -
-

Misc

-
-

-Install a set of useful functions from @bbatsov. The bindings are following -Emacs style instead of being more Vim-like on purpose (I don't want to put -too many things into my leader and these shortcuts look sensible to me). -

- -
- -
(use-package crux
-  :ensure t
-  :config
-
-  (global-set-key (kbd "C-c d") 'crux-delete-file-and-buffer)
-  (global-set-key (kbd "C-c r") 'crux-rename-file-and-buffer)
-  (global-set-key (kbd "C-c o") 'crux-open-with))
-
-
-
-
- -
-

Credits

-
-

-I've built this file by simply scavenging from other people's emacs.d/dotfiles -repositories. I have taken lots of pieces from here and there, but most notably: -

- - -
-
- -
-

License

-
-
- -
Copyright (C) 2014-2018 Miquel Sabaté Solà <mikisabate@gmail.com>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-
-
-
-
-
-

Author: Miquel Sabaté Solà

-

Created: 2018-02-14 Wed 13:15

-

Emacs 25.3.1 (Org mode 8.2.10)

-

Validate

-
- - -- cgit v1.2.3