#+TITLE:
#+PROPERTY: tangle init2.el
#+STARTUP: showall
#+OPTIONS: author:nil num:nil toc:nil
#+MACRO: key @@html:$1@@@@ascii:`$1'@@
#+HTML_HEAD:
* About this file
Inspired by such other projects as the literal Emacs init from [[http://sachac.github.io/.emacs.d/Sacha.html][Sacha
Chua]] and also from [[http://www.wisdomandwonder.com/wordpress/wp-content/uploads/2014/03/C3F.html][Grant Rettke]], here is my Emacs initialization
file.
*Note:* This is not my entire Emacs initialization file. It's a
work-in-progress. To keep on top of any changes to this file, or any
other part of my Emacs init, I recommend you follow [[http://code.ryuslash.org/dot/tom/emacs/][This project]]
([[http://code.ryuslash.org/dot/tom/emacs/atom/?h=master][Atom feed]]), which is where I keep my configuration.
** Preparation
I could use org-babel to load this file, but I don't like my
initialization file being dependent on too many things, especially
big things, and org is a big thing. It may be strange for you to
read this, as I have placed my entire Emacs configuration in an
org-mode file, but here are the make targets I use to tangle and
subsequently byte-compile my init file:
#+BEGIN_SRC makefile :tangle no
%.elc: %.el
emacs -Q -batch -eval "(byte-compile-file \"$<\")"
init.el: init.org
emacs -Q -batch -l "ob-tangle" -eval "(org-babel-tangle-file \"init.org\")
#+END_SRC
Executing the second target (either through make, or manually) will
get you my Emacs initialization file in plain Emacs Lisp.
*Note:* If you look at this file in it's org-mode form you will
notice that I actually tangle ~init.org~ into ~init2.el~. This is a
temporary measure so that I can gradually move my configuration
from my existing ~init.el~ file into ~init.org~ without much trouble.
Once I've emptied out my ~init.el~ I will instruct babel to tangle
into ~init.el~, this code already reflects that.
* Use lexical binding
For some of these functions, and general coolness, lexical binding
is a must. Without it, closures cannot be made.
#+BEGIN_SRC emacs-lisp :padline no
;; -*- lexical-binding: t -*-
#+END_SRC
* Remove some UI elements
Some elements are only really useful if you use the mouse. Which I
don't, not if I can help it. Only when browsing the web or using the
odd graphical application do I touch the mouse, and even then as
little as I can.
** Menu bar
The menu bar is one of the UI elements which work best with mouses.
Sure you can change your toolkit's key bindings to allow you to
more easily navigate, but {{{key(M-x)}}} or {{{key(M-`)}}}[fn:1]
are easier if you don't use the mouse. Long story short: It has got
to go.
#+BEGIN_SRC emacs-lisp
(menu-bar-mode -1)
#+END_SRC
** Tool bar
The toolbar is another such thing, and it takes up quite a bit more
space too. Icons can look pretty cool, but in the end if you're not
going to click them they don't really server much of a purpose.
Again: It has got to go.
#+BEGIN_SRC emacs-lisp
(tool-bar-mode -1)
#+END_SRC
** Scroll bar
The scroll-bar is almost just as informative as the current line
number and buffer position information shown in the (my) mode line.
As I don't usually need to know where I am, other than the current
line number occasionally, and I don't use the mouse, the scroll bar
doesn't add anything and only takes up space. Once more: It has got
to go.
#+BEGIN_SRC emacs-lisp
(scroll-bar-mode -1)
#+END_SRC
** Blinking cursor
I suppose a blinking cursor doesn't get lost very easily. But on
the other hand, it can induce quite a few more headaches.
I've noticed that I don't really lose my cursor position all that
much, really, so there doesn't seem to be any point in making it
blink. Here we go again: It has got to go.
#+BEGIN_SRC emacs-lisp
(blink-cursor-mode -1)
#+END_SRC
** Column and line numbers
As I'm currently using svg-mode-line-themes[fn:2] for my ~mode-line~ I
don't need to show these. Also I didn't really use them much, I
don't often need to know what line I'm on.
#+BEGIN_SRC emacs-lisp
(column-number-mode -1)
(line-number-mode -1)
#+END_SRC
** Tooltips
Tooltips are another one of those UI elements that aren't quite
keyboard-friendly. As usually this information is shown just as well
in the echo area, this is not necessary.
#+BEGIN_SRC emacs-lisp
(tooltip-mode -1)
#+END_SRC
* Add org-mode appointments to the diary
Diary offers reminders, which can be useful when scheduling
appointments.
#+BEGIN_SRC emacs-lisp
(defadvice org-agenda-redo (after ext:org-agenda-redo-add-appts)
"Pressing `r' on the agenda will also add appointments."
(setq appt-time-msg-list nil)
(org-agenda-to-appt))
#+END_SRC
* Close ansi-term buffer after exit
After the ansi-term process ends it leaves a buffer. I don't use
ansi term in such a way that this has ever been useful, so just kill
the ansi-term buffer after the process quits, no matter the exit
status. Usually this comes about when I press {{{kbd(C-d)}}} at the
command prompt.
#+BEGIN_SRC emacs-lisp
(defadvice term-handle-exit (after oni:kill-buffer-after-exit activate)
"Kill the term buffer if the process finished."
(kill-buffer (current-buffer)))
#+END_SRC
* Stumpwm integration
This variable, macro and function help with integrating Emacs and
Stumpwm. They are used by some other functions to make the two seem
extra connected.
#+BEGIN_SRC emacs-lisp
(defvar oni:stumpish-program
(expand-file-name
"~/.local/share/quicklisp/local-projects/stumpwm/contrib/util/stumpish/stumpish")
"The location of the stumpish executable.")
(defmacro oni:stumpwm (&rest body)
"Execute BODY in stumpwm."
(declare (indent 0))
`(call-process oni:stumpish-program nil nil nil
,(format "eval '%S'" `(progn ,@body))))
(defun oni:stumpwm-command (cmd)
"Execute CMD in stumpwm."
(call-process oni:stumpish-program nil nil nil cmd))
(defun oni:stumpwm-echo (message)
(call-process oni:stumpish-program nil nil nil (format "echo %s" message)))
#+END_SRC
** Fall back on stumpwm when moving around
Using the function specified in [[Stumpwm integration]] wrap the
=windmove-do-window-select= function and catch any error produced,
hoping it's the error that there's no more window to move to and
then request that stumpwm move the focus in the same direction as
windmove would have.
#+BEGIN_SRC emacs-lisp
(defadvice windmove-do-window-select
(around oni:windmove-stumpwm activate)
"If no window can be moved to, move stumpwm."
(condition-case err
ad-do-it
(error (oni:stumpwm-command
(format "move-focus %s" (ad-get-arg 0))))))
#+END_SRC
* Don't just quit Emacs with {{{key(C-x C-c)}}} in the daemon
When working with Emacs as a daemon, which I do almost all of the
time, I prefer using {{{key(C-x C-c)}}} to close the current frame
instead of the entire session. Before this change I would
occasionally close my session by mistake.
#+BEGIN_SRC emacs-lisp
(defun oni:close-client-window ()
"Close a client's frames."
(interactive)
(server-save-buffers-kill-terminal nil))
(when (daemonp)
(global-set-key (kbd "C-x C-c") 'oni:close-client-window))
#+END_SRC
* Don't minimize the frame with {{{key(C-z)}}}
One of the more annoying things that can happen is accidentally
minimizing the frame you're working with. This doesn't really matter
if you're working on a normal stacking window manager, but with a
tiling window manager and no task bar this just causes the Emacs
frame to hang until it is refocused or disappear with no way to get
it back.
#+BEGIN_SRC emacs-lisp
(when (or window-system (daemonp))
(global-unset-key (kbd "C-z")))
#+END_SRC
* Use the right dictionary
One of the caveats of using two (or more) languages in a single
installation of Gnus is that ispell sometimes gets confused. Having
come across a stackoverflow question[fn:3] about just this subject
it was easy to modify the source code posted there to come up with
this.
*Note:* See my [[Function declarations][note]] on function declarations about the use of
=declare-function=.
#+BEGIN_SRC emacs-lisp
(declare-function message-narrow-to-headers-or-head "message")
(declare-function message-fetch-field "message")
(defun oni:switch-ispell-dictionary ()
(save-excursion
(message-narrow-to-headers-or-head)
(let ((from (message-fetch-field "From")))
(ispell-change-dictionary
(if (string-match (rx "@aethon.nl>" eol) from) "nl" "en")))))
(add-hook 'message-setup-hook 'oni:switch-ispell-dictionary)
#+END_SRC
* Don't let shr use background color
Reading mail in Gnus is very nice, but shr has become a little too
good at its job. Add to this the many occasions when a background is
specified without specifying a foreground, plus a color theme that
is the inverse of what is usually expected, and you can get
hard-to-read HTML messages, gray foreground and gray background.
I've looked at the other possible renderers, but they don't look
very nice compared to shr. So just remove its ability to add
background colors.
*Note:* See my [[Function declarations][note]] on function declarations about the use of
=declare-function=.
#+BEGIN_SRC emacs-lisp
(declare-function shr-colorize-region "shr")
(defun oni:shr-colorize-remove-last-arg (args)
"If ARGS has more than 3 items, remove the last one."
(if (> (length args) 3)
(butlast args)
args))
(with-eval-after-load 'shr
(advice-add #'shr-colorize-region :filter-args
#'oni:shr-colorize-remove-last-arg))
#+END_SRC
* Optimized ~with-eval-after-load~
First offered [[http://www.lunaryorn.com/2013/05/01/byte-compiling-eval-after-load.html][here]] and then later updated [[http://www.lunaryorn.com/2013/06/25/introducing-with-eval-after-load.html][here]] (when
~with-eval-after-load~ was added). Makes for very nice on-demand
settings loading.
#+BEGIN_SRC emacs-lisp
;; http://www.lunaryorn.com/2013/06/25/introducing-with-eval-after-load/
(defmacro stante-after (feature &rest forms)
"After FEATURE is loaded, evaluate FORMS.
FEATURE may be an unquoted feature symbol or a file name, see
`eval-after-load'."
(declare (indent 1) (debug t))
`(,(if (or (not byte-compile-current-file)
(if (symbolp feature)
(require feature nil :noerror)
(load feature :no-message :no-error)))
`progn
(message "stante-after: cannot find %s" feature)
'with-no-warnings)
(with-eval-after-load ',feature ,@forms)))
#+END_SRC
* Remember SQL input
Remembering input between sessions is a good thing.
#+BEGIN_SRC emacs-lisp
(stante-after sql
(setf sql-input-ring-file-name
(expand-file-name "~/.emacs.d/sqliinput")))
#+END_SRC
* Lazily load some buffers
Don't load all buffers right away. Having a lot of buffers and
switching between projects a lot can take up quite a bit of time.
*Note:* See my [[Vacuous defvar][note]] on vacuous defvar for this use of =defvar=.
#+BEGIN_SRC emacs-lisp
(defvar desktop-restore-eager)
(setq desktop-restore-eager 5)
#+END_SRC
* Fix some term keybindings
=ansi-term= passes along a lot of characters correctly, but things
like =forward-delete-word= are not, by default. This is confusing when
you see one thing and another is sent. Passing the correct keys
directly to the terminal fixes this problem.
*Note:* See my [[Vacuous defvar][note]] on vacuous defvar for this use of =defvar=.
*Note:* See my [[Function declarations][note]] on function declarations about the use of
=declare-function=.
#+BEGIN_SRC emacs-lisp
(defvar term-raw-map)
(declare-function term-send-raw-string "term")
(defun oni:set-term-keys ()
(cl-flet ((zcommand (key)
(lambda ()
(interactive) (term-send-raw-string key))))
(define-key term-raw-map
(kbd "C-") (zcommand "\C-H"))))
(add-hook 'term-mode-hook #'oni:set-term-keys)
#+END_SRC
* Ask for a ~y~ or ~n~, not ~yes~ or ~no~.
Emacs starts out asking for you to type ~yes~ or ~no~ with most
important questions. It is possible that this is used for such
important questions where accidentally saying ~yes~ when you meant ~no~
would be catastrophic (or at least could be). However, I've never
(so far) had this problem, and I find it quite tedious to have to
write out ~yes~ or ~no~ and then press {{{kbd(RET)}}}, give me a simple
~y~ or ~n~ with no {{{kdb(RET)}}} required and I'm quite happy.
#+BEGIN_SRC emacs-lisp
(defalias 'yes-or-no-p 'y-or-n-p)
#+END_SRC
* Use =hippie-expand=, not =dabbrev-expand=
I've never actually used =dabbrev-expand=, and only rarely use
=hippie-expand= really, but since =hippie-expand= also includes a
=dabbrev= expander and a lot more than just that, it seems alright to
do this.
#+BEGIN_SRC emacs-lisp
(defalias 'dabbrev-expand 'hippie-expand)
#+END_SRC
* Notes
Here are some random or somewhat general notes about things you may
run into when looking through my Emacs init.
** Vacuous defvar
A =defvar= without a value like =(defvar some-variable)= tells the
byte-compiler that the variable will appear, but doesn't give it a
value. It should only count for the file where it is used and once
the file with the /actual/ =defvar= is loaded it will be populated with
its value, contrary to what would happen if you'd given it a value
before loading its original file.
** Function declarations
The function =declare-function= tells the byte-compiler where to find
a certain function. This keeps the byte-compiler from complaining
about certain functions possibly not being defined at run-time.
* Footnotes
[fn:1] This runs =tmm-menubar=, which lets you navigate the menubar in a
text-driven way. I don't ever use it because I know what all my
favorite functions are called, but it seems a great deal more
efficient than having to click on everything.
[fn:2] https://github.com/sabof/svg-mode-line-themes
[fn:3] http://stackoverflow.com/questions/22175214/automatically-switch-language-in-gnus-depending-on-recipient